Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions apps/docs/personal-settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ the instructions already shown in the text box active. **Reset** clears both
edited and learned instructions. A reset does not rebuild them from older
conversation history.

Fast captures each participant's personalization when they first speak in a
conversation and keeps that private snapshot for their later turns in the same
conversation. New preferences stated in a message still guide that request and
are saved for future conversations, but they do not rewrite the current
conversation's snapshot. Edits and resets in Personal Settings likewise apply
to new conversations, or to a participant who has not spoken in the current
conversation yet.

Personalization follows the trusted account associated with the current
speaker on supported chat surfaces and with the person who requested a task.
In a shared thread, Roomote adapts its conversation to the current speaker
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 13 additions & 10 deletions packages/cloud-agents/src/server/fast-agent/fast-agent-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import { buildFastAgentSystemPrompt } from './fast-agent-prompt';
import { getTherapistModeEnabledForUser } from '../therapist-mode';
import {
enqueueUserPersonalizationUpdate,
resolveUserPersonalizationContext,
resolveFastAgentPersonalizationContext,
} from '../user-personalization';
import {
appendFastAgentVisibleMessages,
Expand Down Expand Up @@ -2903,7 +2903,6 @@ export async function answerFastAgentQuestion({
discoveredIntegrations,
currentUser,
therapistModeEnabled,
personalizationContext,
agentBehaviorSettings,
] = await Promise.all([
getAvailableEnvironments(),
Expand Down Expand Up @@ -2944,14 +2943,6 @@ export async function answerFastAgentQuestion({
);
return false;
}),
platformEvent
? Promise.resolve(null)
: resolveUserPersonalizationContext(userId).catch((error) => {
console.warn(
`[Fast Agent] User personalization unavailable: ${formatErrorForLog(error)}`,
);
return null;
}),
db.query.deploymentSettings
.findFirst({
columns: {
Expand All @@ -2967,6 +2958,17 @@ export async function answerFastAgentQuestion({
return undefined;
}),
]);
const personalizationContext = platformEvent
? null
: await resolveFastAgentPersonalizationContext({
conversationId: session.id,
userId,
}).catch((error) => {
console.warn(
`[Fast Agent] User personalization unavailable: ${formatErrorForLog(error)}`,
);
return null;
});
if (model === undefined) model = session.model;
if (reasoningEffort === undefined)
reasoningEffort = session.reasoningEffort;
Expand Down Expand Up @@ -4451,6 +4453,7 @@ export async function answerFastAgentQuestion({
const args = updatePersonalizationArgsSchema.parse(call.args);
const result = await enqueueUserPersonalizationUpdate({
userId,
fastConversationId: session.id,
...args,
});
return result.saved
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions packages/cloud-agents/src/server/user-personalization.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
appendLearnedUserPreference,
getOrCreateFastAgentPersonalizationSnapshot,
getUserPersonalizationRuntimeContext,
type UserPersonalization,
} from '@roomote/db/server';
Expand All @@ -22,6 +23,7 @@ type QueuedPersonalizationUpdate = {
preference: string;
confidence: 'explicit' | 'inferred';
taskId?: string | null;
fastConversationId?: string;
};

type PersonalizationUpdateResult = Awaited<
Expand All @@ -43,6 +45,13 @@ export async function resolveUserPersonalizationContext(
return getUserPersonalizationRuntimeContext(userId);
}

export async function resolveFastAgentPersonalizationContext(input: {
conversationId: string;
userId: string;
}) {
return getOrCreateFastAgentPersonalizationSnapshot(input);
}

export function buildUserPersonalizationInstructions(
context:
| {
Expand Down Expand Up @@ -156,6 +165,9 @@ export function enqueueUserPersonalizationUpdate(
preference: decision.preference,
confidence: input.confidence,
supersedes: decision.supersedes,
...(input.fastConversationId
? { fastConversationId: input.fastConversationId }
: {}),
});
})
.finally(() => {
Expand Down
12 changes: 12 additions & 0 deletions packages/db/drizzle/0084_confused_frightful_four.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CREATE TABLE "fast_agent_personalization_snapshots" (
"conversation_id" uuid NOT NULL,
"user_id" text NOT NULL,
"display_name" text,
"instructions" text NOT NULL,
"learn_from_conversations" boolean NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "fast_agent_personalization_snapshots_conversation_id_user_id_pk" PRIMARY KEY("conversation_id","user_id")
);
--> statement-breakpoint
ALTER TABLE "fast_agent_personalization_snapshots" ADD CONSTRAINT "fast_agent_personalization_snapshots_conversation_id_fast_agent_conversations_id_fk" FOREIGN KEY ("conversation_id") REFERENCES "public"."fast_agent_conversations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "fast_agent_personalization_snapshots" ADD CONSTRAINT "fast_agent_personalization_snapshots_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
Loading
Loading