feat(profile): /api/profile + eligibility filter + inference framework (ADR-0014 steps 4-6)
Step 4 — /api/profile read-through API:
GET /api/profile → { user, prefs, consents, contexts }
PATCH /api/profile/prefs/:scope upsert user_preferences (source='user')
PATCH /api/profile/consents grant / revoke consent keys
PATCH /api/profile/contexts create / activate / deactivate contexts
Legacy consentGiven bit folded in as data:core fallback.
Step 5 — registry-driven eligibility filter:
fetchRegistry() exported from agent-registry.ts.
profile/eligibility.ts: getEligibleAgentIds(userId) — filters by required
consents, silenced_in_contexts, and user_preferences[enabled=false].
fetchOrchestratorTip filters agent_outputs to eligible set before calling
ml/serving /recommend. Fail-closed: registry unavailable → empty set.
Step 6 — shared context-inference framework (#111) + time-of-day proof (#112):
ml/agents/inference/: UserHistory, FeedbackEvent, run_inference().
Framework: cold-start, min_history gating, error fallback, structured logs.
TimeOfDayAgent v1.1.0: inferred_params=[preferred_hour]; also reads
quiet_start/quiet_end from agent_prefs. agent_prefs injected by TS caller.
AgentInput gains agent_prefs field.
ml/serving: POST /agents/{agent_id}/infer endpoint.
agent-outputs.ts computeAndStore: loads prefs before compute, calls /infer
after, persists results (source='inferred'); user overrides never touched.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { todoistSource, dueAgeDays } from '../signals/todoist.js';
|
||||
export { dueAgeDays };
|
||||
import { SignalAggregator } from '../signals/aggregator.js';
|
||||
import { getActiveAgentOutputs } from './agent-outputs.js';
|
||||
import { getEligibleAgentIds } from '../profile/eligibility.js';
|
||||
|
||||
const router: ExpressRouter = Router();
|
||||
|
||||
@@ -58,11 +59,13 @@ async function fetchOrchestratorTip(
|
||||
dayOfWeek: number,
|
||||
traceparent?: string,
|
||||
): Promise<OrchestratorResult | null> {
|
||||
const agentRows = await getActiveAgentOutputs(userId);
|
||||
const agentOutputs = agentRows.map((r) => ({
|
||||
agent_id: r.agentId,
|
||||
prompt_text: r.promptText,
|
||||
}));
|
||||
const [allAgentRows, eligibleIds] = await Promise.all([
|
||||
getActiveAgentOutputs(userId),
|
||||
getEligibleAgentIds(userId),
|
||||
]);
|
||||
const agentOutputs = allAgentRows
|
||||
.filter((r) => eligibleIds.has(r.agentId))
|
||||
.map((r) => ({ agent_id: r.agentId, prompt_text: r.promptText }));
|
||||
|
||||
const tasks = signals.slice(0, 10).map((s) => ({
|
||||
content: s.content,
|
||||
|
||||
Reference in New Issue
Block a user