Core Concepts
Outcome Reporting
Help CogniKin learn by reporting what happened after each interaction.
Why Report Outcomes?
Outcome reporting is how CogniKin learns what works for each user. Without outcomes, CogniKin can't improve its recommendations.
Without Outcomes
- ❌ CogniKin uses population defaults forever
- ❌ No personalisation happens
- ❌ Recommendations stay generic
- ❌ Wasted potential
With Outcomes
- ✅ CogniKin learns user preferences
- ✅ Recommendations improve over time
- ✅ Completion rates increase
- ✅ Users are more engaged
The reportOutcome() Call
After a user interacts with your agent's response, report what happened:
await brain.reportOutcome({
requestId: context.requestId, // From getContext() response
started: true, // Did user start the task?
completed: true, // Did they complete it?
timeToStart: 45, // Optional: seconds until started
flowState: true, // Optional: were they engaged?
satisfaction: 0.9, // Optional: explicit feedback (0-1)
});Required Parameters
| Parameter | Type | Description |
|---|---|---|
| requestId | string | The ID from getContext() response |
| started | boolean | Did the user start working on the task? |
Optional Parameters
| Parameter | Type | Description |
|---|---|---|
| completed | boolean | Did they complete the task? |
| timeToStart | number | Seconds from response to starting (lower is better) |
| flowState | boolean | Did they seem deeply engaged? (in flow) |
| satisfaction | number | Explicit user feedback score (0-1) |
| metadata | object | Additional context about the outcome |
Outcome Patterns
Pattern 1: Successful Completion
// User started immediately and completed successfully
await brain.reportOutcome({
requestId: context.requestId,
started: true,
completed: true,
timeToStart: 10,
flowState: true,
satisfaction: 0.95
});
// CogniKin learns: This approach worked really wellPattern 2: Started But Not Completed
// User started but got stuck or gave up
await brain.reportOutcome({
requestId: context.requestId,
started: true,
completed: false,
timeToStart: 30,
flowState: false
});
// CogniKin learns: This approach wasn't quite rightPattern 3: Never Started
// User didn't even start the task
await brain.reportOutcome({
requestId: context.requestId,
started: false,
completed: false
});
// CogniKin learns: This approach didn't motivate the user at allPattern 4: Delayed Start
// User hesitated but eventually started and completed
await brain.reportOutcome({
requestId: context.requestId,
started: true,
completed: true,
timeToStart: 300, // 5 minutes delay
flowState: false
});
// CogniKin learns: Approach worked but wasn't immediately motivatingWhen to Report Outcomes
Immediate vs Delayed Reporting
You can report outcomes immediately or after a delay:
// Option 1: Immediate (optimistic)
const context = await brain.getContext({ userId, task });
const response = await generateResponse(context);
// Assume success and report immediately
await brain.reportOutcome({
requestId: context.requestId,
started: true,
completed: true // Optimistic assumption
});
// Option 2: Delayed (accurate)
const context = await brain.getContext({ userId, task });
const response = await generateResponse(context);
// Wait for actual user behaviour
setTimeout(async () => {
const actualOutcome = await trackUserBehaviour();
await brain.reportOutcome({
requestId: context.requestId,
...actualOutcome
});
}, 60000); // 1 minute delayBackground Reporting
Report outcomes in the background to avoid blocking:
// Don't await - fire and forget
brain.reportOutcome({
requestId: context.requestId,
started: true,
completed: userCompletedTask
}).catch(err => {
// Log errors but don't fail the main flow
console.error('Outcome reporting failed:', err);
});Tracking User Behaviour
Detecting If User Started
// Track if user took action after response
const userActivity = {
started: false,
completed: false,
timeToStart: null
};
const startTime = Date.now();
// Listen for user actions
on('user:action', () => {
if (!userActivity.started) {
userActivity.started = true;
userActivity.timeToStart = (Date.now() - startTime) / 1000;
}
});
// Check completion
on('task:complete', () => {
userActivity.completed = true;
});Detecting Flow State
// Heuristics for detecting flow state
function detectFlowState(userSession) {
const indicators = {
// Continuous activity without long pauses
continuousActivity: userSession.longestPause < 30,
// High interaction rate
highInteractionRate: userSession.actionsPerMinute > 3,
// Minimal context switching
focused: userSession.tabSwitches < 2,
// Quick responses to prompts
quickResponses: userSession.avgResponseTime < 10
};
// Flow state if most indicators are true
const flowScore = Object.values(indicators)
.filter(v => v).length / Object.keys(indicators).length;
return flowScore > 0.7;
}Gathering Satisfaction Scores
// Ask for explicit feedback
const feedback = await askUser({
question: "How helpful was this response?",
scale: "1-5 stars"
});
await brain.reportOutcome({
requestId: context.requestId,
started: true,
completed: true,
satisfaction: feedback.rating / 5 // Normalize to 0-1
});Outcome Weights
Not all outcomes are weighted equally in CogniKin's learning:
| Outcome | Signal Strength | Impact |
|---|---|---|
| Never started | Strong negative | Decreases confidence in approach |
| Started + Completed | Strong positive | Increases confidence in approach |
| Started + Not Completed | Weak negative | Slight decrease in confidence |
| Flow State = true | Bonus positive | Extra confidence boost |
| Low timeToStart | Positive modifier | Indicates strong motivation |
Best Practices
Do ✅
- Always report outcomes, even negative ones
- Track real user behaviour, not assumptions
- Include optional parameters when available
- Report outcomes even for failed interactions
- Use background reporting to avoid blocking
Don't ❌
- Report overly optimistic outcomes
- Skip reporting when outcomes are bad
- Report before user has chance to act
- Block main flow waiting for outcome calls
- Report outcomes for wrong requestId
Error Handling
try {
await brain.reportOutcome({
requestId: context.requestId,
started: userStarted,
completed: userCompleted
});
} catch (error) {
// Log but don't fail
console.error('Failed to report outcome:', error);
// Optionally queue for retry
outcomeQueue.push({
requestId: context.requestId,
outcome: { started: userStarted, completed: userCompleted },
retries: 0
});
}💡 Pro Tip: The more accurate your outcome reporting, the faster CogniKin learns. Track real user behaviour rather than making optimistic assumptions.