-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy patheducational-microcopy.ts
More file actions
266 lines (227 loc) · 9.91 KB
/
Copy patheducational-microcopy.ts
File metadata and controls
266 lines (227 loc) · 9.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/**
* Educational Microcopy - Teaching users about the AI-to-human artifact bridge
*
* These one-liners help users understand the value of persistent context
* and artifacts that survive ephemeral AI conversations.
*
* Principles:
* - Token-efficient (< 15 words)
* - Actionable where possible
* - Show value, don't lecture
*/
// ============================================================================
// Session Init Tips - Shown on every session start (rotating)
// ============================================================================
export const SESSION_INIT_TIPS = [
"AI work that doesn't disappear.",
"Every conversation builds context. Every artifact persists.",
"Your AI remembers. Now you can see what it knows.",
"Context that survives sessions.",
"The bridge between AI conversations and human artifacts.",
];
/**
* Get a rotating tip for session init based on simple hash of session ID
*/
export function getSessionInitTip(sessionId?: string): string {
const index = sessionId
? Math.abs(hashString(sessionId)) % SESSION_INIT_TIPS.length
: Math.floor(Math.random() * SESSION_INIT_TIPS.length);
return SESSION_INIT_TIPS[index];
}
// ============================================================================
// Capture Success Hints - Contextual hints based on what was captured
// ============================================================================
export const CAPTURE_HINTS: Record<string, string> = {
// Core event types
decision: "Future you will thank present you.",
preference: "Noted. This will inform future suggestions.",
insight: "Captured for future reference.",
note: "Saved. Won't disappear when the chat does.",
implementation: "Implementation recorded.",
task: "Task tracked.",
bug: "Bug logged for tracking.",
feature: "Feature request captured.",
plan: "This plan will be here when you come back.",
correction: "Correction noted. Learning from this.",
lesson: "Learn once, remember forever.",
warning: "Warning logged.",
frustration: "Feedback captured. We're listening.",
conversation: "Conversation preserved.",
session_snapshot: "Session state saved. Ready to resume anytime.",
};
/**
* Get the appropriate hint for a captured event type
*/
export function getCaptureHint(eventType: string): string {
return CAPTURE_HINTS[eventType] || "Captured. This will survive when the chat disappears.";
}
// ============================================================================
// Empty State Messages - When queries return no results
// ============================================================================
export const EMPTY_STATE_HINTS: Record<string, string> = {
// Plans
list_plans: "No plans yet. Plans live here, not in chat transcripts.",
get_plan: "Plan not found. Create one to track implementation across sessions.",
// Memory & Search
recall: "Nothing found yet. Context builds over time.",
search: "No matches. Try a different query or let context accumulate.",
list_events: "No events yet. Start capturing decisions and insights.",
decisions: "No decisions captured yet. Record the 'why' behind your choices.",
timeline: "Timeline empty. Events will appear as you work.",
// Lessons
get_lessons: "No lessons yet. Capture mistakes to learn from them.",
// Tasks
list_tasks: "No tasks yet. Break plans into trackable tasks.",
// Todos
list_todos: "No todos yet. Action items will appear here.",
// Diagrams
list_diagrams: "No diagrams yet. AI-generated diagrams persist here.",
// Docs
list_docs: "No docs yet. Turn AI explanations into shareable documentation.",
// Reminders
list_reminders: "No reminders set. Schedule follow-ups that won't be forgotten.",
// Generic
default: "Nothing yet. Start a conversation—context builds over time.",
};
/**
* Get the appropriate empty state hint for a given action
*/
export function getEmptyStateHint(action: string): string {
return EMPTY_STATE_HINTS[action] || EMPTY_STATE_HINTS.default;
}
// ============================================================================
// Post-Compaction Messages - When restoring context after session end
// ============================================================================
export const POST_COMPACT_HINTS = {
restored: "Picked up where you left off. Session ended, memory didn't.",
restored_with_session: (sessionId: string) =>
`Restored from session ${sessionId}. Session ended, memory didn't.`,
no_snapshot: "No prior session found. Fresh start—context will build as you work.",
failed: "Couldn't restore previous session. Use context to retrieve what you need.",
};
// ============================================================================
// Plan Lifecycle Hints - For plan state transitions
// ============================================================================
export const PLAN_HINTS: Record<string, string> = {
created: "Plan saved. It will be here when you come back.",
activated: "Plan is now active. Track progress across sessions.",
completed: "Plan completed. The journey is preserved for future reference.",
abandoned: "Plan archived. Abandoned plans still teach.",
updated: "Plan updated. Changes are preserved.",
};
/**
* Get hint for plan status change
*/
export function getPlanStatusHint(status: string): string {
const statusMap: Record<string, string> = {
draft: PLAN_HINTS.created,
active: PLAN_HINTS.activated,
completed: PLAN_HINTS.completed,
abandoned: PLAN_HINTS.abandoned,
archived: PLAN_HINTS.abandoned,
};
return statusMap[status] || PLAN_HINTS.updated;
}
// ============================================================================
// Task Lifecycle Hints
// ============================================================================
export const TASK_HINTS: Record<string, string> = {
created: "Task tracked. It won't disappear when the chat does.",
completed: "Task done. Progress is preserved.",
blocked: "Task blocked. Capture what's blocking for future reference.",
cancelled: "Task cancelled. The history remains.",
};
// ============================================================================
// Integration Hints - For connected services
// ============================================================================
export const INTEGRATION_HINTS: Record<string, string> = {
not_connected:
"Connect integrations to sync context where your team already works.",
slack: "Context from Slack conversations, connected.",
github: "Issues and PRs linked to the decisions behind them.",
notion: "Decisions synced to where your team documents.",
};
// ============================================================================
// Search Result Hints - When search finds results
// ============================================================================
export const SEARCH_HINTS = {
found: (count: number) =>
count === 1
? "Found 1 match from your AI history."
: `Found ${count} matches from your AI history.`,
semantic: "Results ranked by meaning, not just keywords.",
exhaustive: "Complete search across all indexed content.",
};
// ============================================================================
// Context Tips - Occasional tips in context responses (used sparingly)
// ============================================================================
export const CONTEXT_TIPS = [
"Search everything AI ever helped you with.",
"Find that thing the AI explained three weeks ago.",
"Decisions captured here inform future AI suggestions.",
];
/**
* Get a context tip (returns undefined most of the time to avoid noise)
* Only returns a tip ~10% of the time
*/
export function getContextTip(callCount?: number): string | undefined {
// If we have a call count, show tip every 10th call
if (callCount !== undefined) {
return callCount % 10 === 0 ? CONTEXT_TIPS[callCount % CONTEXT_TIPS.length] : undefined;
}
// Random 10% chance
if (Math.random() < 0.1) {
return CONTEXT_TIPS[Math.floor(Math.random() * CONTEXT_TIPS.length)];
}
return undefined;
}
// ============================================================================
// Memory/Artifact Specific Hints
// ============================================================================
export const ARTIFACT_HINTS: Record<string, string> = {
diagram: "AI drew this. Now it's yours to keep and share.",
doc: "From conversation to documentation.",
roadmap: "Roadmap persisted. Track progress across sessions.",
todo: "Action item captured. It won't disappear when the chat does.",
};
// ============================================================================
// Workspace & Project Hints
// ============================================================================
export const WORKSPACE_HINTS = {
created: "Workspace ready. Context that spans projects.",
associated: "Folder linked. Decisions here inform AI across sessions.",
switched: "Workspace switched. Each workspace has its own memory.",
};
export const PROJECT_HINTS = {
created: "Project indexed. Your codebase, searchable.",
indexed: "Indexing complete. AI now understands your code structure.",
ingest_started: "Indexing started. Code context builds in the background.",
};
// ============================================================================
// Helper Functions
// ============================================================================
/**
* Simple string hash function for deterministic tip selection
*/
function hashString(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
/**
* Format a hint for inclusion in a response
* Adds the hint field if hint is provided
*/
export function addHintToResponse<T extends Record<string, unknown>>(
response: T,
hint: string | undefined
): T & { hint?: string } {
if (hint) {
return { ...response, hint };
}
return response;
}