Skip to content

Conversations (Autonomous)

A conversation agent lets several agents collaborate in a dialogue. Each agent takes a turn and adds to a shared chat history.

Two modes are available:

  • Round-robin: agents take turns in a fixed order
  • AI-driven: a moderator agent decides who speaks next

Agents speak in the order of the list. Each agent sees the full conversation history and adds its perspective. The conversation continues to a termination condition, or to the maximum number of turns.

Three agents collaborate on a party plan. A brainstormer proposes ideas. A critic evaluates each idea. A synthesizer merges the best ideas into a plan.

Step 1: Create prompt profiles for each participant:

DECLARE
l_profile_id NUMBER;
BEGIN
l_profile_id := uc_ai_prompt_profiles_api.create_prompt_profile(
p_code => 'party_brainstormer_profile',
p_description => 'Brainstorms creative party ideas',
p_system_prompt_template => 'You are Brainstormer. Propose 2-3 creative party ideas based on the task and chat history. Be enthusiastic! Structure: "Idea 1: [desc]. Idea 2: [desc]." Reference recent messages.',
p_user_prompt_template => 'Generate or refine party ideas: {prompt}. Your role: {role}.',
p_provider => uc_ai.c_provider_openai,
p_model => uc_ai_openai.c_model_gpt_5_6_luna,
p_status => uc_ai_prompt_profiles_api.c_status_active
);
l_profile_id := uc_ai_prompt_profiles_api.create_prompt_profile(
p_code => 'party_critic_profile',
p_description => 'Critiques party ideas for budget, safety, and feasibility',
p_system_prompt_template => 'You are Critic. Analyze previous ideas: check budget, safety, and practical limits. Suggest fixes or reject bad ideas. Structure: "Critique: [idea] is [good/bad because...]. Fix: [suggestion]." Be realistic.',
p_user_prompt_template => 'Chat history: {prompt}. Your role: {role}.',
p_provider => uc_ai.c_provider_openai,
p_model => uc_ai_openai.c_model_gpt_5_6_luna,
p_status => uc_ai_prompt_profiles_api.c_status_active
);
l_profile_id := uc_ai_prompt_profiles_api.create_prompt_profile(
p_code => 'party_synthesizer_profile',
p_description => 'Synthesizes ideas into a cohesive party plan with cost estimates',
p_system_prompt_template => 'You are Synthesizer. Merge good ideas from history into 1 polished plan. Estimate total cost. Structure: "Combined Plan: 1. [activity] ($X). 2. [food] ($Y). Total: $Z." If you finalize, say "Final Plan: ..."',
p_user_prompt_template => 'Chat history: {prompt}. Your role: {role}.',
p_provider => uc_ai.c_provider_openai,
p_model => uc_ai_openai.c_model_gpt_5_6_luna,
p_status => uc_ai_prompt_profiles_api.c_status_active
);
COMMIT;
END;
/

Step 2: Create profile agents for each participant:

DECLARE
l_agent_id NUMBER;
BEGIN
l_agent_id := uc_ai_agents_api.create_agent(
p_code => 'brainstormer_agent',
p_description => 'Creative brainstormer who proposes party ideas',
p_agent_type => uc_ai_agents_api.c_type_profile,
p_prompt_profile_code => 'party_brainstormer_profile',
p_status => uc_ai_agents_api.c_status_active
);
l_agent_id := uc_ai_agents_api.create_agent(
p_code => 'critic_agent',
p_description => 'Practical critic who checks feasibility and budget',
p_agent_type => uc_ai_agents_api.c_type_profile,
p_prompt_profile_code => 'party_critic_profile',
p_status => uc_ai_agents_api.c_status_active
);
l_agent_id := uc_ai_agents_api.create_agent(
p_code => 'synthesizer_agent',
p_description => 'Synthesizer who merges ideas into a final plan',
p_agent_type => uc_ai_agents_api.c_type_profile,
p_prompt_profile_code => 'party_synthesizer_profile',
p_status => uc_ai_agents_api.c_status_active
);
COMMIT; -- agents must be committed before they can be executed
END;
/

Step 3: Create the conversation agent:

DECLARE
l_conv_id NUMBER;
l_conv_config CLOB;
BEGIN
l_conv_config := '{
"pattern_type": "conversation",
"conversation_mode": "round_robin",
"agents": [
{
"agent_code": "brainstormer_agent",
"input_mapping": {
"prompt": "{$.chat_history}",
"role": "{$.agent_description}"
}
},
{
"agent_code": "critic_agent",
"input_mapping": {
"prompt": "{$.chat_history}",
"role": "{$.agent_description}"
}
},
{
"agent_code": "synthesizer_agent",
"input_mapping": {
"prompt": "{$.chat_history}",
"role": "{$.agent_description}"
}
}
],
"max_turns": 3,
"termination_condition": {
"type": "keyword_in_response",
"keyword": "Final Plan"
}
}';
l_conv_id := uc_ai_agents_api.create_agent(
p_code => 'party_planning_roundrobin',
p_description => 'Party planning with brainstormer, critic, and synthesizer',
p_agent_type => uc_ai_agents_api.c_type_conversation,
p_orchestration_config => l_conv_config,
p_max_iterations => 2,
p_status => uc_ai_agents_api.c_status_active
);
COMMIT;
END;
/

Step 4: Execute:

DECLARE
l_result json_object_t;
BEGIN
l_result := uc_ai_agents_api.execute_agent(
p_agent_code => 'party_planning_roundrobin',
p_input_parameters => json_object_t('{
"prompt": "Plan a birthday party for a 12 year old who loves pirates and football. Max 14 kids, $200 budget."
}'),
p_session_id => uc_ai_agents_api.generate_session_id
);
DBMS_OUTPUT.PUT_LINE('Result: ' || l_result.get_clob('final_message'));
END;
/

How it works:

  1. Each turn, agents speak in order: brainstormer, critic, synthesizer
  2. Each agent receives the full conversation history via {$.chat_history} and its own role description via {$.agent_description}
  3. The conversation ends when an agent writes “Final Plan” in its answer, or at max_turns

A moderator agent decides who speaks next. The order is therefore not fixed: the moderator directs the discussion at each turn.

Keep the participant agents from above. Then add a moderator that steers the conversation:

Step 1: Create the moderator prompt profile:

DECLARE
l_profile_id NUMBER;
BEGIN
l_profile_id := uc_ai_prompt_profiles_api.create_prompt_profile(
p_code => 'party_moderator_profile',
p_description => 'Moderates the party planning conversation',
p_system_prompt_template => 'You are the Moderator. Oversee the party planning conversation. Decide who speaks next based on the chat history. If you think there is a solid plan ready, you can finalize the conversation. When done, summarize the final plan for the user.',
p_user_prompt_template => '{prompt}',
p_provider => uc_ai.c_provider_openai,
p_model => uc_ai_openai.c_model_gpt_5_6_luna,
p_status => uc_ai_prompt_profiles_api.c_status_active
);
COMMIT;
END;
/

Then create the moderator profile agent:

DECLARE
l_agent_id NUMBER;
BEGIN
l_agent_id := uc_ai_agents_api.create_agent(
p_code => 'moderator_agent',
p_description => 'Moderator who decides which agent speaks next',
p_agent_type => uc_ai_agents_api.c_type_profile,
p_prompt_profile_code => 'party_moderator_profile',
p_status => uc_ai_agents_api.c_status_active
);
END;
/

Step 2: Create the AI-driven conversation agent:

DECLARE
l_conv_id NUMBER;
l_conv_config CLOB;
BEGIN
l_conv_config := '{
"pattern_type": "conversation",
"conversation_mode": "ai_driven",
"moderator_agent": {
"agent_code": "moderator_agent",
"input_mapping": {
"prompt": "Chat history: {$.chat_history} | Available agents: {$.available_agents}"
},
"summary_mapping": {
"prompt": "The conversation was ended. Please outline the final plan for the user. Max 2 sentences. | Chat history: {$.chat_history}"
}
},
"max_turns": 6,
"agents": [
{
"agent_code": "brainstormer_agent",
"input_mapping": {
"prompt": "{$.chat_history}",
"role": "{$.agent_description} | Why you were picked: {$.moderator_rationale}"
}
},
{
"agent_code": "critic_agent",
"input_mapping": {
"prompt": "{$.chat_history}",
"role": "{$.agent_description} | Why you were picked: {$.moderator_rationale}"
}
},
{
"agent_code": "synthesizer_agent",
"input_mapping": {
"prompt": "{$.chat_history}",
"role": "{$.agent_description} | Why you were picked: {$.moderator_rationale}"
}
}
]
}';
l_conv_id := uc_ai_agents_api.create_agent(
p_code => 'party_planning_ai_driven',
p_description => 'AI-moderated party planning discussion',
p_agent_type => uc_ai_agents_api.c_type_conversation,
p_orchestration_config => l_conv_config,
p_max_iterations => 1,
p_status => uc_ai_agents_api.c_status_active
);
COMMIT;
END;
/

Step 3: Execute:

DECLARE
l_result json_object_t;
BEGIN
l_result := uc_ai_agents_api.execute_agent(
p_agent_code => 'party_planning_ai_driven',
p_input_parameters => json_object_t('{
"prompt": "Plan a birthday party for a 12 year old who loves pirates and football. Max 14 kids, $200 budget."
}'),
p_session_id => uc_ai_agents_api.generate_session_id
);
DBMS_OUTPUT.PUT_LINE('Final plan: ' || l_result.get_clob('final_message'));
END;
/

How it works:

  1. The moderator receives the chat history and the list of available agents via {$.available_agents}
  2. It decides which agent speaks next, and gives a reason
  3. The selected agent speaks. It receives the chat history, and the reason of the moderator in {$.moderator_rationale}
  4. When the moderator ends the conversation, UC AI uses the summary_mapping for a final summary
  5. The conversation ends after max_turns, or when the moderator finishes it

UC AI stores a conversation turn in uc_ai_agent_messages as a full transcript. The opening input is a user row. Each participant turn is one assistant row, and its agent_code names the agent that produced it. In AI-driven mode, the closing summary of the moderator is the last row. There are no tool rows, because a conversation is a discussion and not tool use.

SELECT seq, role, agent_code, SUBSTR(content, 1, 60) AS content
FROM uc_ai_agent_messages
WHERE session_id = :session_id
ORDER BY seq;
seqroleagent_codecontent
1user(null){"prompt":"Plan a birthday party for a 12 ...
2assistantbrainstormer_agentIdea 1: Pirate Football Treasure Hunt - ...
3assistantcritic_agentCritique: the treasure hunt is risky because...
4assistantsynthesizer_agentCombined Plan: 1. Pirate Football Scavenger...
5assistantmoderator_agentFinal Party Plan: ... (AI-driven summary)

Filter by agent_code to see the contributions of one participant. Read the rows in seq order to replay the discussion.

FieldTypeDescription
pattern_typeStringMust be "conversation"
conversation_modeString"round_robin" or "ai_driven"
agentsArrayParticipant agents with their input mappings
max_turnsNumberMaximum conversation turns
termination_conditionObject(Round-robin) When to stop early
moderator_agentObject(AI-driven) The moderator agent config
moderator_agent.summary_mappingObject(AI-driven) Input mapping for generating the final summary
"termination_condition": {
"type": "keyword_in_response",
"keyword": "Final Plan"
}

The conversation stops early when the answer of any agent holds the keyword.

The moderator has two input mappings:

  • input_mapping: UC AI uses it each turn, to decide who speaks next
  • summary_mapping: UC AI uses it once at the end, for the final summary

An input mapping of a conversation agent can use these variables:

VariableDescriptionAvailable to
{$.chat_history}Full conversation historyAll participants
{$.agent_description}The description of the current agentAll participants
{$.available_agents}List of agents with descriptionsModerator only
{$.moderator_rationale}Why this agent was picked to speakParticipants in AI-driven mode
  • Give each agent a distinct personality: write a clear role in the system prompt of each agent. An overlap gives repeated answers.
  • Use the agent description as context: pass {$.agent_description} to each agent, so that it knows its role in the conversation. One prompt template can then serve several roles.
  • Keep max_turns small: each turn calls an AI model. A round-robin with 3 agents and max_turns: 5 makes up to 15 AI calls.
  • Termination keywords: in round-robin mode, instruct the last agent to write a keyword such as “Final Plan” at the end of the discussion.
  • Moderator instructions: in AI-driven mode, tell the moderator when to finish. Without this instruction, it continues to max_turns.