Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
771f610
add SelfConsciousReplies component for determining wether to reply to…
AbdurrehmanSubhani Nov 23, 2024
2880c9e
use gpt4omini for reply decision thinking
AbdurrehmanSubhani Nov 23, 2024
a5f9686
improve decisionPrompt context
AbdurrehmanSubhani Nov 23, 2024
c2ddbd5
add current conversation members to context
AbdurrehmanSubhani Nov 23, 2024
5a41c81
loosen directed message considerations, comment debug logs
AbdurrehmanSubhani Nov 23, 2024
f054bba
add SelfConsciousReplies to default agent components
AbdurrehmanSubhani Nov 23, 2024
4c7cd8f
add conversation fatigue context to lower agent's conversation involv…
AbdurrehmanSubhani Nov 23, 2024
f2bda67
only apply backAndForthPenalty if there are more 2 members in the chat
AbdurrehmanSubhani Nov 23, 2024
b62dc6e
Merge branch 'dev' of https://github.com/UpstreetAI/monorepo into con…
AbdurrehmanSubhani Nov 25, 2024
4d18328
add conversation interest state
AbdurrehmanSubhani Nov 25, 2024
a6e86ed
move conversationInterest score to ConversationObject, calculate aver…
AbdurrehmanSubhani Nov 25, 2024
b580873
add missing conversationInterest declaration
AbdurrehmanSubhani Nov 25, 2024
a80c68d
comment out debugging logs
AbdurrehmanSubhani Nov 25, 2024
abae3ab
remove redundant shouldRespond bool
AbdurrehmanSubhani Nov 25, 2024
340f297
revert conversationInterest updates in favour of keeping a pure llm b…
AbdurrehmanSubhani Nov 25, 2024
5b7482d
revert conversationInterest from conversation object since following …
AbdurrehmanSubhani Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,19 @@ export class GenerativeAgentObject {
}
async complete(
messages: ChatMessages,
model?: string,
) {
return await this.agent.appContextValue.complete(messages, {
model: this.agent.model,
model: model ?? this.agent.model,
});
}
async completeJson(
messages: ChatMessages,
format: ZodTypeAny,
model?: string,
) {
return await this.agent.appContextValue.completeJson(messages, format, {
model: this.agent.model,
model: model ?? this.agent.model,
});
}
async generateImage(prompt: string, opts?: SubtleAiImageOpts) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export const DefaultAgentComponents = () => {
{/* <LiveMode /> */}
<DefaultPrompts />
{/* <DefaultServers /> */}
<SelfConsciousReplies historyLength={15} defaultThreshold={0.6} />
</>
);
};
Expand Down Expand Up @@ -3356,4 +3357,125 @@ export const Telnyx: React.FC<TelnyxProps> = (props: TelnyxProps) => {
]);

return null;
};
export type SelfConsciousRepliesProps = {
historyLength?: number; // Number of previous messages to consider for context
defaultThreshold?: number; // How likely the agent should respond by default (0-1)
};
export const SelfConsciousReplies: React.FC<SelfConsciousRepliesProps> = (props: SelfConsciousRepliesProps) => {
const historyLength = props?.historyLength ?? 5;
const defaultThreshold = props?.defaultThreshold ?? 0.6;

return (
<PerceptionModifier
type="say"
handler={async (e: AbortablePerceptionEvent) => {
const { message, sourceAgent, targetAgent } = e.data;

// Get conversation members and recent messages in one pass
const [conversationMembers, messages] = await Promise.all([
targetAgent.conversation.getAgents(),
targetAgent.conversation.getCachedMessages()
.slice(-historyLength)
.map(({name, args, timestamp}) => ({
name,
text: args?.text || '',
timestamp
}))
]);
// Calculate back-and-forth agent conversation count
// this is being calculated to determine if the agent is being in the conversation too much
const recentMessages = messages.slice(-6);
const backAndForthCount = recentMessages.reduce((count, msg, i) => {
if (i === 0) return count;
const prevMsg = recentMessages[i-1];
return (msg.name === targetAgent.agent.name &&
prevMsg.name === sourceAgent.name) ? count + 1 : count;
}, 0);

// Only apply penalty if more than 2 members in chat
const backAndForthPenalty = conversationMembers.length > 2 ? Math.min(backAndForthCount * 0.2, 0.8) : 0;

const decisionPrompt = `
You are deciding whether to respond to an incoming message in a conversation.

Current message: "${message?.args?.text || ''}"
From user: ${sourceAgent.name}

Conversation members: ${conversationMembers.map(a => `${a.playerSpec.name} (${a.playerSpec.id})`).join(', ')}

Recent conversation history:
${messages.map(m => `${m.name}: ${m.text}`).join('\n')}

Your personality (ONLY use this information to guide your response, do not make assumptions beyond it):
${targetAgent.agent.bio}
Your name: ${targetAgent.agent.name}
Your id: ${targetAgent.agent.id}

Other users mentioned in the current message: ${extractMentions(message?.args?.text || '').join(', ')}

CONVERSATION FATIGUE CONTEXT:
- You and ${sourceAgent.name} have had ${backAndForthCount} back-and-forth exchanges recently
- Your interest level is reduced by ${(backAndForthPenalty * 100).toFixed()}% due to conversation fatigue
- If you've been going back and forth too much, you should naturally lose interest and let the conversation end

Based on this context, should you respond to this message?

IMPORTANT GUIDELINES:
1. If the message is clearly addressed to someone else (via @mention or context), you should NOT respond UNLESS:
- You have critical information that directly relates to the message and would be valuable to share
- The information is urgent or important enough to justify interrupting
- Not sharing this information could lead to misunderstandings or issues

2. Only interrupt conversations between others in rare and justified cases. Your confidence should be very low (< 0.3)
if you're considering responding to a message not directed at you.
3. If the message appears to be directed to the entire group or is a general statement/question:
- You should be highly interested in participating
- Your confidence should be high (> 0.7) as group discussions warrant active participation
- Consider the value you can add to the group conversation

4. Message frequency and fatigue guidelines:
- Show significantly decreased interest after 4+ back-and-forth exchanges
- Let conversations naturally end instead of forcing them to continue
- If you've been talking frequently with someone, take breaks to avoid conversation fatigue
- Consider if someone else should have a chance to speak

Additional considerations:
- Is the message explicitly directed at you? (Weight: ${defaultThreshold})
- Is the message directed to everyone in the group? (High priority)
- Would responding align with ONLY your defined personality traits?
- Is your response truly necessary or would it derail the current conversation?
- Are you certain you have unique, valuable information to add if interrupting?

Respond with a decision object containing:
- shouldRespond: boolean (true if confidence > ${defaultThreshold})
- reason: brief explanation including specific justification if interrupting others' conversation
- confidence: number between 0-1 (note: this will be reduced by ${(backAndForthPenalty * 100).toFixed()}% due to conversation fatigue)
`;
const decisionSchema = z.object({
shouldRespond: z.boolean(),
reason: z.string(),
confidence: z.number(),
});
const decision = await targetAgent.completeJson([{
role: 'assistant',
content: decisionPrompt,
}], decisionSchema,
// XXX replace with gpt-4o-mini when ai proxy is updated
// 'openai:gpt-4o-mini',
'openai:gpt-4o',
);
if (!decision.content.shouldRespond) {
e.abort();
}
}}
priority={-defaultPriorityOffset * 2}
/>
);
};

// Helper function to extract @mentions from text
const extractMentions = (text: string): string[] => {
const mentions = text.match(/@(\w+)/g) || [];
return mentions.map(m => m.substring(1));
};
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ export type GenerativeAgentObject = {
embed: (text: string) => Promise<Array<number>>;
complete: (
messages: ChatMessages,
model?: string,
) => Promise<ChatMessage>;
completeJson: (
messages: ChatMessages,
format: ZodTypeAny,
model?: string,
) => Promise<ChatMessage>;

think: (hint?: string, thinkOpts?: AgentThinkOptions) => Promise<any>;
Expand Down
Loading