diff --git a/packages/usdk/packages/upstreet-agent/packages/react-agents/classes/generative-agent-object.ts b/packages/usdk/packages/upstreet-agent/packages/react-agents/classes/generative-agent-object.ts
index 2f1cd0219..bcba817a0 100644
--- a/packages/usdk/packages/upstreet-agent/packages/react-agents/classes/generative-agent-object.ts
+++ b/packages/usdk/packages/upstreet-agent/packages/react-agents/classes/generative-agent-object.ts
@@ -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) {
diff --git a/packages/usdk/packages/upstreet-agent/packages/react-agents/default-components.tsx b/packages/usdk/packages/upstreet-agent/packages/react-agents/default-components.tsx
index 7d6d2b31e..dd1db4e3f 100644
--- a/packages/usdk/packages/upstreet-agent/packages/react-agents/default-components.tsx
+++ b/packages/usdk/packages/upstreet-agent/packages/react-agents/default-components.tsx
@@ -142,6 +142,7 @@ export const DefaultAgentComponents = () => {
{/* */}
{/* */}
+
>
);
};
@@ -3356,4 +3357,125 @@ export const Telnyx: React.FC = (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 = (props: SelfConsciousRepliesProps) => {
+ const historyLength = props?.historyLength ?? 5;
+ const defaultThreshold = props?.defaultThreshold ?? 0.6;
+
+ return (
+ {
+ 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));
};
\ No newline at end of file
diff --git a/packages/usdk/packages/upstreet-agent/packages/react-agents/types/agents.d.ts b/packages/usdk/packages/upstreet-agent/packages/react-agents/types/agents.d.ts
index e2f72835b..54f01c5cf 100644
--- a/packages/usdk/packages/upstreet-agent/packages/react-agents/types/agents.d.ts
+++ b/packages/usdk/packages/upstreet-agent/packages/react-agents/types/agents.d.ts
@@ -52,10 +52,12 @@ export type GenerativeAgentObject = {
embed: (text: string) => Promise>;
complete: (
messages: ChatMessages,
+ model?: string,
) => Promise;
completeJson: (
messages: ChatMessages,
format: ZodTypeAny,
+ model?: string,
) => Promise;
think: (hint?: string, thinkOpts?: AgentThinkOptions) => Promise;