@burdenoff/microfe-buildmyiq 2026.1013.1 → 2026.1024.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/buildmyiq/components/GroundedTutorPanel.d.ts +33 -0
- package/dist/buildmyiq/components/GroundedTutorPanel.d.ts.map +1 -0
- package/dist/buildmyiq/components/GroundedTutorPanel.js +197 -0
- package/dist/buildmyiq/components/GroundedTutorPanel.js.map +1 -0
- package/dist/buildmyiq/components/TutorPanel.d.ts +5 -1
- package/dist/buildmyiq/components/TutorPanel.d.ts.map +1 -1
- package/dist/buildmyiq/components/TutorPanel.js +20 -12
- package/dist/buildmyiq/components/TutorPanel.js.map +1 -1
- package/dist/buildmyiq/hooks/useBuildmyiqApi.d.ts +16 -0
- package/dist/buildmyiq/hooks/useBuildmyiqApi.d.ts.map +1 -1
- package/dist/buildmyiq/hooks/useBuildmyiqApi.js +185 -129
- package/dist/buildmyiq/hooks/useBuildmyiqApi.js.map +1 -1
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.js +16 -13
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GroundedTutorPanel — the native 24/7 AI tutor chat for a lesson (BOFF-4426).
|
|
3
|
+
* @module buildmyiq/components/GroundedTutorPanel
|
|
4
|
+
*
|
|
5
|
+
* Rendered by `TutorPanel` for every course that has no course teacher
|
|
6
|
+
* (a configured course assistant) bound, so every lesson has a working,
|
|
7
|
+
* content-grounded tutor without any per-course setup.
|
|
8
|
+
*
|
|
9
|
+
* Grounded Q&A: every assistant answer comes from `buiTutorAsk`, which
|
|
10
|
+
* retrieves the actual lesson content server-side before calling the model
|
|
11
|
+
* (see `TutorService.retrieveGrounding` in wspace-buildmyiq-svc) — never an
|
|
12
|
+
* ungrounded chat completion. Continues the learner's own session for this
|
|
13
|
+
* lesson (multi-turn) via `useBuiMyTutorSessions` / `useBuiTutorAsk`.
|
|
14
|
+
*
|
|
15
|
+
* Each assistant turn carries the `groundingLessonIds` the answer was actually
|
|
16
|
+
* derived from; they are rendered as source chips so the learner can see which
|
|
17
|
+
* lesson content backs the answer instead of taking it on trust. Ids the caller
|
|
18
|
+
* cannot name are shown as-is rather than guessed at or hidden.
|
|
19
|
+
*/
|
|
20
|
+
interface GroundedTutorPanelProps {
|
|
21
|
+
lessonId: string;
|
|
22
|
+
lessonTitle: string;
|
|
23
|
+
/**
|
|
24
|
+
* Titles for the lessons the tutor may ground an answer in, keyed by lesson
|
|
25
|
+
* id — supplied by the host page, which has already loaded the course. Only
|
|
26
|
+
* used to LABEL the ids the server returned; a missing entry falls back to
|
|
27
|
+
* the raw id, never to an invented title.
|
|
28
|
+
*/
|
|
29
|
+
lessonTitlesById?: ReadonlyMap<string, string>;
|
|
30
|
+
}
|
|
31
|
+
export declare function GroundedTutorPanel({ lessonId, lessonTitle, lessonTitlesById, }: GroundedTutorPanelProps): import("react").JSX.Element;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=GroundedTutorPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroundedTutorPanel.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/components/GroundedTutorPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAWH,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChD;AAmBD,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,WAAW,EACX,gBAAgB,GACjB,EAAE,uBAAuB,+BAoMzB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { useBuildmyiq as e } from "../context/BuildmyiqContext.js";
|
|
2
|
+
import "../context/index.js";
|
|
3
|
+
import { useTr as t } from "../shared/hooks/useTr.js";
|
|
4
|
+
import { LoadingView as n } from "./StateViews.js";
|
|
5
|
+
import { useBuiMyTutorSessions as r, useBuiTutorAsk as i } from "../hooks/useBuildmyiqApi.js";
|
|
6
|
+
import "../hooks/index.js";
|
|
7
|
+
import { useEffect as a, useRef as o, useState as s } from "react";
|
|
8
|
+
import { BookOpen as c, Bot as l, Send as u, Sparkles as d } from "lucide-react";
|
|
9
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
10
|
+
import { Button as m, GlassCard as h, Textarea as g } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
//#region src/buildmyiq/components/GroundedTutorPanel.tsx
|
|
12
|
+
function _(e) {
|
|
13
|
+
let t = e.trim();
|
|
14
|
+
return t ? t[0].toUpperCase() : "?";
|
|
15
|
+
}
|
|
16
|
+
var v = {
|
|
17
|
+
STRUGGLING: "Extra step-by-step help — based on your recent scores",
|
|
18
|
+
ON_TRACK: "Standard depth",
|
|
19
|
+
ADVANCED: "Deeper dive — based on your recent scores"
|
|
20
|
+
};
|
|
21
|
+
function y(e) {
|
|
22
|
+
if (!e) return "You";
|
|
23
|
+
let t = [e.firstName, e.lastName].filter(Boolean).join(" ").trim();
|
|
24
|
+
return e.name || t || e.username || e.email || "You";
|
|
25
|
+
}
|
|
26
|
+
function b({ lessonId: b, lessonTitle: x, lessonTitlesById: S }) {
|
|
27
|
+
let { currentUser: C } = e(), w = t(), T = r(b), E = i(), [D, O] = s(void 0), [k, A] = s(""), [j, M] = s(null), [N, P] = s(null), F = o(null), I = T.data?.[0], L = D ? T.data?.find((e) => e.id === D)?.messages ?? [] : I?.messages ?? [];
|
|
28
|
+
a(() => {
|
|
29
|
+
F.current?.scrollTo({
|
|
30
|
+
top: F.current.scrollHeight,
|
|
31
|
+
behavior: "smooth"
|
|
32
|
+
});
|
|
33
|
+
}, [L.length, N]);
|
|
34
|
+
let R = T.isSuccess, z = y(C), B = (e) => e === b ? x : S?.get(e) ?? e, V = async () => {
|
|
35
|
+
let e = k.trim();
|
|
36
|
+
if (!(!e || !R)) {
|
|
37
|
+
M(null), A(""), P(e);
|
|
38
|
+
try {
|
|
39
|
+
O((await E.mutateAsync({
|
|
40
|
+
lessonId: b,
|
|
41
|
+
question: e,
|
|
42
|
+
sessionId: D ?? I?.id
|
|
43
|
+
})).session.id);
|
|
44
|
+
} catch (t) {
|
|
45
|
+
M(t instanceof Error ? t.message : "The AI tutor is temporarily unavailable."), A(e);
|
|
46
|
+
} finally {
|
|
47
|
+
P(null);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return /* @__PURE__ */ p(h, {
|
|
52
|
+
treatment: "plain",
|
|
53
|
+
className: "flex flex-col overflow-hidden p-0",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ p("div", {
|
|
56
|
+
className: "flex items-center gap-2 border-b border-border-seam px-4 py-3",
|
|
57
|
+
children: [/* @__PURE__ */ f("span", {
|
|
58
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)]",
|
|
59
|
+
children: /* @__PURE__ */ f(d, { className: "h-4 w-4 text-[var(--color-accent-teal)]" })
|
|
60
|
+
}), /* @__PURE__ */ p("div", {
|
|
61
|
+
className: "min-w-0",
|
|
62
|
+
children: [/* @__PURE__ */ f("p", {
|
|
63
|
+
className: "text-sm font-semibold text-text-primary",
|
|
64
|
+
children: "AI Tutor"
|
|
65
|
+
}), /* @__PURE__ */ p("p", {
|
|
66
|
+
className: "truncate text-xs text-text-secondary",
|
|
67
|
+
children: [
|
|
68
|
+
"Grounded in “",
|
|
69
|
+
x,
|
|
70
|
+
"”"
|
|
71
|
+
]
|
|
72
|
+
})]
|
|
73
|
+
})]
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ f("div", {
|
|
76
|
+
ref: F,
|
|
77
|
+
className: "max-h-96 min-h-40 flex-1 overflow-y-auto px-4 py-4",
|
|
78
|
+
children: T.isLoading ? /* @__PURE__ */ f(n, { label: "Loading your tutor conversation…" }) : L.length === 0 ? /* @__PURE__ */ p("div", {
|
|
79
|
+
className: "flex flex-col items-center gap-2 py-6 text-center",
|
|
80
|
+
children: [/* @__PURE__ */ f(l, { className: "h-8 w-8 text-text-tertiary" }), /* @__PURE__ */ f("p", {
|
|
81
|
+
className: "text-sm text-text-secondary",
|
|
82
|
+
children: "Ask a question about this lesson — the tutor answers from the lesson content, with hints first."
|
|
83
|
+
})]
|
|
84
|
+
}) : /* @__PURE__ */ p("ul", {
|
|
85
|
+
className: "flex flex-col gap-4",
|
|
86
|
+
children: [
|
|
87
|
+
L.map((e) => {
|
|
88
|
+
let t = e.role === "ASSISTANT";
|
|
89
|
+
return /* @__PURE__ */ p("li", {
|
|
90
|
+
className: "flex gap-3",
|
|
91
|
+
children: [/* @__PURE__ */ f("div", {
|
|
92
|
+
className: t ? "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)]" : "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-secondary",
|
|
93
|
+
children: t ? /* @__PURE__ */ f(l, { className: "h-4 w-4 text-[var(--color-accent-teal)]" }) : _(z)
|
|
94
|
+
}), /* @__PURE__ */ p("div", {
|
|
95
|
+
className: "min-w-0 flex-1",
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ p("div", {
|
|
98
|
+
className: "flex flex-wrap items-baseline gap-x-2",
|
|
99
|
+
children: [/* @__PURE__ */ f("span", {
|
|
100
|
+
className: "text-sm font-semibold text-text-primary",
|
|
101
|
+
children: t ? "AI Tutor" : z
|
|
102
|
+
}), t && e.adaptiveLevel && /* @__PURE__ */ f("span", {
|
|
103
|
+
className: "text-xs text-text-tertiary",
|
|
104
|
+
children: v[e.adaptiveLevel]
|
|
105
|
+
})]
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ f("p", {
|
|
108
|
+
className: "mt-0.5 whitespace-pre-wrap break-words text-sm text-text-secondary",
|
|
109
|
+
children: e.content
|
|
110
|
+
}),
|
|
111
|
+
t && e.groundingLessonIds.length > 0 && /* @__PURE__ */ p("div", {
|
|
112
|
+
className: "mt-2 flex flex-wrap items-center gap-1.5",
|
|
113
|
+
children: [/* @__PURE__ */ p("span", {
|
|
114
|
+
className: "inline-flex items-center gap-1 text-xs text-text-tertiary",
|
|
115
|
+
children: [/* @__PURE__ */ f(c, { className: "h-3.5 w-3.5" }), w("buildmyiq.tutor.groundedIn", "Answered from")]
|
|
116
|
+
}), e.groundingLessonIds.map((e) => /* @__PURE__ */ f("span", {
|
|
117
|
+
title: e,
|
|
118
|
+
className: "max-w-[14rem] truncate rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
|
|
119
|
+
children: B(e)
|
|
120
|
+
}, e))]
|
|
121
|
+
})
|
|
122
|
+
]
|
|
123
|
+
})]
|
|
124
|
+
}, e.id);
|
|
125
|
+
}),
|
|
126
|
+
N && /* @__PURE__ */ p("li", {
|
|
127
|
+
className: "flex gap-3",
|
|
128
|
+
children: [/* @__PURE__ */ f("div", {
|
|
129
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-secondary",
|
|
130
|
+
children: _(z)
|
|
131
|
+
}), /* @__PURE__ */ p("div", {
|
|
132
|
+
className: "min-w-0 flex-1",
|
|
133
|
+
children: [/* @__PURE__ */ f("span", {
|
|
134
|
+
className: "text-sm font-semibold text-text-primary",
|
|
135
|
+
children: z
|
|
136
|
+
}), /* @__PURE__ */ f("p", {
|
|
137
|
+
className: "mt-0.5 whitespace-pre-wrap break-words text-sm text-text-secondary",
|
|
138
|
+
children: N
|
|
139
|
+
})]
|
|
140
|
+
})]
|
|
141
|
+
}),
|
|
142
|
+
E.isPending && /* @__PURE__ */ p("li", {
|
|
143
|
+
className: "flex items-center gap-3",
|
|
144
|
+
children: [/* @__PURE__ */ f("span", {
|
|
145
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)]",
|
|
146
|
+
children: /* @__PURE__ */ f(l, { className: "h-4 w-4 animate-pulse text-[var(--color-accent-teal)]" })
|
|
147
|
+
}), /* @__PURE__ */ f("span", {
|
|
148
|
+
className: "text-sm text-text-secondary",
|
|
149
|
+
children: "Thinking…"
|
|
150
|
+
})]
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
})
|
|
154
|
+
}),
|
|
155
|
+
/* @__PURE__ */ p("div", {
|
|
156
|
+
className: "border-t border-border-seam p-3",
|
|
157
|
+
children: [/* @__PURE__ */ f(g, {
|
|
158
|
+
value: k,
|
|
159
|
+
onChange: (e) => A(e.target.value),
|
|
160
|
+
onKeyDown: (e) => {
|
|
161
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), V());
|
|
162
|
+
},
|
|
163
|
+
placeholder: "Ask about this lesson…",
|
|
164
|
+
rows: 2,
|
|
165
|
+
disabled: E.isPending || !R
|
|
166
|
+
}), /* @__PURE__ */ p("div", {
|
|
167
|
+
className: "mt-2 flex items-center justify-end gap-2",
|
|
168
|
+
children: [
|
|
169
|
+
j && /* @__PURE__ */ f("span", {
|
|
170
|
+
className: "mr-auto text-xs text-status-error-text",
|
|
171
|
+
children: j
|
|
172
|
+
}),
|
|
173
|
+
T.isError && !j && /* @__PURE__ */ p("span", {
|
|
174
|
+
className: "mr-auto flex items-center gap-2 text-xs text-status-error-text",
|
|
175
|
+
children: ["Your tutor history could not be loaded.", /* @__PURE__ */ f(m, {
|
|
176
|
+
size: "sm",
|
|
177
|
+
variant: "outline",
|
|
178
|
+
onClick: () => void T.refetch(),
|
|
179
|
+
children: "Retry"
|
|
180
|
+
})]
|
|
181
|
+
}),
|
|
182
|
+
/* @__PURE__ */ p(m, {
|
|
183
|
+
size: "sm",
|
|
184
|
+
onClick: V,
|
|
185
|
+
disabled: !k.trim() || E.isPending || !R,
|
|
186
|
+
children: [/* @__PURE__ */ f(u, { className: "mr-1.5 h-4 w-4" }), E.isPending ? "Asking…" : "Ask"]
|
|
187
|
+
})
|
|
188
|
+
]
|
|
189
|
+
})]
|
|
190
|
+
})
|
|
191
|
+
]
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
195
|
+
export { b as GroundedTutorPanel };
|
|
196
|
+
|
|
197
|
+
//# sourceMappingURL=GroundedTutorPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroundedTutorPanel.js","names":[],"sources":["../../../src/buildmyiq/components/GroundedTutorPanel.tsx"],"sourcesContent":["/**\n * GroundedTutorPanel — the native 24/7 AI tutor chat for a lesson (BOFF-4426).\n * @module buildmyiq/components/GroundedTutorPanel\n *\n * Rendered by `TutorPanel` for every course that has no course teacher\n * (a configured course assistant) bound, so every lesson has a working,\n * content-grounded tutor without any per-course setup.\n *\n * Grounded Q&A: every assistant answer comes from `buiTutorAsk`, which\n * retrieves the actual lesson content server-side before calling the model\n * (see `TutorService.retrieveGrounding` in wspace-buildmyiq-svc) — never an\n * ungrounded chat completion. Continues the learner's own session for this\n * lesson (multi-turn) via `useBuiMyTutorSessions` / `useBuiTutorAsk`.\n *\n * Each assistant turn carries the `groundingLessonIds` the answer was actually\n * derived from; they are rendered as source chips so the learner can see which\n * lesson content backs the answer instead of taking it on trust. Ids the caller\n * cannot name are shown as-is rather than guessed at or hidden.\n */\n\nimport { useEffect, useRef, useState } from 'react';\nimport { Bot, BookOpen, Send, Sparkles } from 'lucide-react';\nimport { Button, GlassCard, Textarea } from '@burdenoff/fe-libs/ui';\nimport { LoadingView } from './StateViews';\nimport { useBuiMyTutorSessions, useBuiTutorAsk } from '../hooks';\nimport { useBuildmyiq } from '../context';\nimport { useTr } from '../shared/hooks/useTr';\nimport type { BuiTutorAdaptiveLevel, BuiTutorMessage } from '../types';\n\ninterface GroundedTutorPanelProps {\n lessonId: string;\n lessonTitle: string;\n /**\n * Titles for the lessons the tutor may ground an answer in, keyed by lesson\n * id — supplied by the host page, which has already loaded the course. Only\n * used to LABEL the ids the server returned; a missing entry falls back to\n * the raw id, never to an invented title.\n */\n lessonTitlesById?: ReadonlyMap<string, string>;\n}\n\nfunction initialFor(label: string): string {\n const trimmed = label.trim();\n return trimmed ? trimmed[0]!.toUpperCase() : '?';\n}\n\nconst ADAPTIVE_LABEL: Record<BuiTutorAdaptiveLevel, string> = {\n STRUGGLING: 'Extra step-by-step help — based on your recent scores',\n ON_TRACK: 'Standard depth',\n ADVANCED: 'Deeper dive — based on your recent scores',\n};\n\nfunction displayName(user: ReturnType<typeof useBuildmyiq>['currentUser']): string {\n if (!user) return 'You';\n const full = [user.firstName, user.lastName].filter(Boolean).join(' ').trim();\n return user.name || full || user.username || user.email || 'You';\n}\n\nexport function GroundedTutorPanel({\n lessonId,\n lessonTitle,\n lessonTitlesById,\n}: GroundedTutorPanelProps) {\n const { currentUser } = useBuildmyiq();\n const tr = useTr();\n const sessionsQuery = useBuiMyTutorSessions(lessonId);\n const ask = useBuiTutorAsk();\n\n const [sessionId, setSessionId] = useState<string | undefined>(undefined);\n const [draft, setDraft] = useState('');\n const [error, setError] = useState<string | null>(null);\n // Echo of the question in flight, shown until the refetched transcript lands.\n const [pendingQuestion, setPendingQuestion] = useState<string | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Resume the learner's most recently active session for this lesson, if any.\n const existingSession = sessionsQuery.data?.[0];\n const messages: BuiTutorMessage[] = sessionId\n ? (sessionsQuery.data?.find((s) => s.id === sessionId)?.messages ?? [])\n : (existingSession?.messages ?? []);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' });\n }, [messages.length, pendingQuestion]);\n\n // Asking before the history loads would start a second conversation instead\n // of continuing the learner's existing one, so the composer waits for it.\n const historyReady = sessionsQuery.isSuccess;\n\n const selfName = displayName(currentUser);\n\n /** Label a grounding lesson id; an id we can't name is shown verbatim. */\n const groundingLabel = (id: string): string => {\n if (id === lessonId) return lessonTitle;\n return lessonTitlesById?.get(id) ?? id;\n };\n\n const handleAsk = async () => {\n const question = draft.trim();\n if (!question || !historyReady) return;\n setError(null);\n setDraft('');\n setPendingQuestion(question);\n try {\n const result = await ask.mutateAsync({\n lessonId,\n question,\n sessionId: sessionId ?? existingSession?.id,\n });\n setSessionId(result.session.id);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'The AI tutor is temporarily unavailable.');\n setDraft(question);\n } finally {\n setPendingQuestion(null);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n void handleAsk();\n }\n };\n\n return (\n <GlassCard treatment=\"plain\" className=\"flex flex-col overflow-hidden p-0\">\n <div className=\"flex items-center gap-2 border-b border-border-seam px-4 py-3\">\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)]\">\n <Sparkles className=\"h-4 w-4 text-[var(--color-accent-teal)]\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold text-text-primary\">AI Tutor</p>\n <p className=\"truncate text-xs text-text-secondary\">Grounded in “{lessonTitle}”</p>\n </div>\n </div>\n\n <div ref={scrollRef} className=\"max-h-96 min-h-40 flex-1 overflow-y-auto px-4 py-4\">\n {sessionsQuery.isLoading ? (\n <LoadingView label=\"Loading your tutor conversation…\" />\n ) : messages.length === 0 ? (\n <div className=\"flex flex-col items-center gap-2 py-6 text-center\">\n <Bot className=\"h-8 w-8 text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary\">\n Ask a question about this lesson — the tutor answers from the lesson content, with\n hints first.\n </p>\n </div>\n ) : (\n <ul className=\"flex flex-col gap-4\">\n {messages.map((message) => {\n const isAssistant = message.role === 'ASSISTANT';\n return (\n <li key={message.id} className=\"flex gap-3\">\n <div\n className={\n isAssistant\n ? 'flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)]'\n : 'flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-secondary'\n }\n >\n {isAssistant ? (\n <Bot className=\"h-4 w-4 text-[var(--color-accent-teal)]\" />\n ) : (\n initialFor(selfName)\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-2\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {isAssistant ? 'AI Tutor' : selfName}\n </span>\n {isAssistant && message.adaptiveLevel && (\n <span className=\"text-xs text-text-tertiary\">\n {ADAPTIVE_LABEL[message.adaptiveLevel]}\n </span>\n )}\n </div>\n <p className=\"mt-0.5 whitespace-pre-wrap break-words text-sm text-text-secondary\">\n {message.content}\n </p>\n {isAssistant && message.groundingLessonIds.length > 0 && (\n <div className=\"mt-2 flex flex-wrap items-center gap-1.5\">\n <span className=\"inline-flex items-center gap-1 text-xs text-text-tertiary\">\n <BookOpen className=\"h-3.5 w-3.5\" />\n {tr('buildmyiq.tutor.groundedIn', 'Answered from')}\n </span>\n {message.groundingLessonIds.map((groundingId) => (\n <span\n key={groundingId}\n title={groundingId}\n className=\"max-w-[14rem] truncate rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {groundingLabel(groundingId)}\n </span>\n ))}\n </div>\n )}\n </div>\n </li>\n );\n })}\n {pendingQuestion && (\n <li className=\"flex gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-secondary\">\n {initialFor(selfName)}\n </div>\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-sm font-semibold text-text-primary\">{selfName}</span>\n <p className=\"mt-0.5 whitespace-pre-wrap break-words text-sm text-text-secondary\">\n {pendingQuestion}\n </p>\n </div>\n </li>\n )}\n {ask.isPending && (\n <li className=\"flex items-center gap-3\">\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)]\">\n <Bot className=\"h-4 w-4 animate-pulse text-[var(--color-accent-teal)]\" />\n </span>\n <span className=\"text-sm text-text-secondary\">Thinking…</span>\n </li>\n )}\n </ul>\n )}\n </div>\n\n <div className=\"border-t border-border-seam p-3\">\n <Textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Ask about this lesson…\"\n rows={2}\n disabled={ask.isPending || !historyReady}\n />\n <div className=\"mt-2 flex items-center justify-end gap-2\">\n {error && <span className=\"mr-auto text-xs text-status-error-text\">{error}</span>}\n {sessionsQuery.isError && !error && (\n <span className=\"mr-auto flex items-center gap-2 text-xs text-status-error-text\">\n Your tutor history could not be loaded.\n <Button size=\"sm\" variant=\"outline\" onClick={() => void sessionsQuery.refetch()}>\n Retry\n </Button>\n </span>\n )}\n <Button\n size=\"sm\"\n onClick={handleAsk}\n disabled={!draft.trim() || ask.isPending || !historyReady}\n >\n <Send className=\"mr-1.5 h-4 w-4\" />\n {ask.isPending ? 'Asking…' : 'Ask'}\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
interface TutorPanelProps {
|
|
2
2
|
courseId: string;
|
|
3
|
+
enrollmentId: string;
|
|
4
|
+
lessonId: string;
|
|
3
5
|
lessonTitle: string;
|
|
6
|
+
/** Titles for the course's lessons, used to label grounding sources. */
|
|
7
|
+
lessonTitlesById?: ReadonlyMap<string, string>;
|
|
4
8
|
}
|
|
5
|
-
export declare function TutorPanel({ courseId, lessonTitle }: TutorPanelProps): import("react").JSX.Element;
|
|
9
|
+
export declare function TutorPanel({ courseId, enrollmentId, lessonId, lessonTitle, lessonTitlesById, }: TutorPanelProps): import("react").JSX.Element;
|
|
6
10
|
export {};
|
|
7
11
|
//# sourceMappingURL=TutorPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TutorPanel.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/components/TutorPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TutorPanel.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/components/TutorPanel.tsx"],"names":[],"mappings":"AAeA,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChD;AAED,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,gBAAgB,GACjB,EAAE,eAAe,+BA0BjB"}
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
import { useBuildmyiq as e } from "../context/BuildmyiqContext.js";
|
|
2
2
|
import "../context/index.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { LoadingView as t } from "./StateViews.js";
|
|
4
|
+
import { useBuiTutorMode as n } from "../hooks/useBuildmyiqApi.js";
|
|
5
|
+
import "../hooks/index.js";
|
|
6
|
+
import { GroundedTutorPanel as r } from "./GroundedTutorPanel.js";
|
|
7
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
8
|
+
import { WorkflowAssistantPanel as a } from "@burdenoff/fe-libs/shared/assistant";
|
|
5
9
|
//#region src/buildmyiq/components/TutorPanel.tsx
|
|
6
|
-
function
|
|
7
|
-
let { currentUser:
|
|
8
|
-
return /* @__PURE__ */ t(
|
|
10
|
+
function o({ courseId: o, enrollmentId: s, lessonId: c, lessonTitle: l, lessonTitlesById: u }) {
|
|
11
|
+
let { currentUser: d, workspaceId: f, authToken: p } = e(), m = n(s);
|
|
12
|
+
return m.isLoading ? /* @__PURE__ */ i(t, { label: "Loading the AI tutor…" }) : m.data === "teacher" ? /* @__PURE__ */ i(a, {
|
|
9
13
|
target: {
|
|
10
14
|
kind: "buildmyiq-course",
|
|
11
|
-
courseId:
|
|
15
|
+
courseId: o
|
|
12
16
|
},
|
|
13
17
|
context: {
|
|
14
|
-
workspaceId:
|
|
15
|
-
authContext: { accessToken:
|
|
18
|
+
workspaceId: f ?? "",
|
|
19
|
+
authContext: { accessToken: p }
|
|
16
20
|
},
|
|
17
|
-
ownerId:
|
|
21
|
+
ownerId: d?.id ?? "",
|
|
18
22
|
title: "AI Tutor",
|
|
19
|
-
description: `Answers from your course content. Current lesson: “${
|
|
20
|
-
})
|
|
23
|
+
description: `Answers from your course content. Current lesson: “${l}”`
|
|
24
|
+
}) : /* @__PURE__ */ i(r, {
|
|
25
|
+
lessonId: c,
|
|
26
|
+
lessonTitle: l,
|
|
27
|
+
lessonTitlesById: u
|
|
28
|
+
}, c);
|
|
21
29
|
}
|
|
22
30
|
//#endregion
|
|
23
|
-
export {
|
|
31
|
+
export { o as TutorPanel };
|
|
24
32
|
|
|
25
33
|
//# sourceMappingURL=TutorPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TutorPanel.js","names":[],"sources":["../../../src/buildmyiq/components/TutorPanel.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"TutorPanel.js","names":[],"sources":["../../../src/buildmyiq/components/TutorPanel.tsx"],"sourcesContent":["/**\n * TutorPanel — the lesson player's AI tutor (BOFF-4426).\n * @module buildmyiq/components/TutorPanel\n *\n * A course with a bound course teacher uses the shared Fluidgrids workflow\n * assistant. Every other course falls back to the native grounded tutor, so a\n * learner never sees a tutor that cannot answer just because no educator has\n * configured a course teacher yet.\n */\nimport { WorkflowAssistantPanel } from '@burdenoff/fe-libs/shared/assistant';\nimport { useBuildmyiq } from '../context';\nimport { useBuiTutorMode } from '../hooks';\nimport { GroundedTutorPanel } from './GroundedTutorPanel';\nimport { LoadingView } from './StateViews';\n\ninterface TutorPanelProps {\n courseId: string;\n enrollmentId: string;\n lessonId: string;\n lessonTitle: string;\n /** Titles for the course's lessons, used to label grounding sources. */\n lessonTitlesById?: ReadonlyMap<string, string>;\n}\n\nexport function TutorPanel({\n courseId,\n enrollmentId,\n lessonId,\n lessonTitle,\n lessonTitlesById,\n}: TutorPanelProps) {\n const { currentUser, workspaceId, authToken } = useBuildmyiq();\n const mode = useBuiTutorMode(enrollmentId);\n\n if (mode.isLoading) return <LoadingView label=\"Loading the AI tutor…\" />;\n\n if (mode.data === 'teacher') {\n return (\n <WorkflowAssistantPanel\n target={{ kind: 'buildmyiq-course', courseId }}\n context={{ workspaceId: workspaceId ?? '', authContext: { accessToken: authToken } }}\n ownerId={currentUser?.id ?? ''}\n title=\"AI Tutor\"\n description={`Answers from your course content. Current lesson: “${lessonTitle}”`}\n />\n );\n }\n\n return (\n <GroundedTutorPanel\n key={lessonId}\n lessonId={lessonId}\n lessonTitle={lessonTitle}\n lessonTitlesById={lessonTitlesById}\n />\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,EAAW,EACzB,aACA,iBACA,aACA,gBACA,uBACkB;CAClB,IAAM,EAAE,gBAAa,gBAAa,iBAAc,EAAa,GACvD,IAAO,EAAgB,CAAY;CAgBzC,OAdI,EAAK,YAAkB,kBAAC,GAAD,EAAa,OAAM,wBAAyB,CAAA,IAEnE,EAAK,SAAS,YAEd,kBAAC,GAAD;EACE,QAAQ;GAAE,MAAM;GAAoB;EAAS;EAC7C,SAAS;GAAE,aAAa,KAAe;GAAI,aAAa,EAAE,aAAa,EAAU;EAAE;EACnF,SAAS,GAAa,MAAM;EAC5B,OAAM;EACN,aAAa,sDAAsD,EAAY;CAChF,CAAA,IAKH,kBAAC,GAAD;EAEY;EACG;EACK;CACnB,GAJM,CAIN;AAEL"}
|
|
@@ -164,6 +164,22 @@ export declare const useBuiCertificates: (courseId?: string, enabled?: boolean)
|
|
|
164
164
|
export declare const useBuiMyCertificates: (courseId?: string, enabled?: boolean) => import('@tanstack/react-query').UseQueryResult<NoInfer<BuiCertificate[]>, Error>;
|
|
165
165
|
export declare const useBuiIssueCertificate: () => import('@tanstack/react-query').UseMutationResult<BuiCertificate, Error, BuiIssueCertificateInput, unknown>;
|
|
166
166
|
export declare const useBuiRevokeCertificate: () => import('@tanstack/react-query').UseMutationResult<BuiCertificate, Error, string, unknown>;
|
|
167
|
+
/**
|
|
168
|
+
* Which tutor the lesson player shows for an enrollment.
|
|
169
|
+
* - `teacher`: an educator bound a course teacher (course assistant) to the
|
|
170
|
+
* course, so the Fluidgrids workflow assistant answers from its knowledge base.
|
|
171
|
+
* - `native`: no course teacher is bound, so the built-in grounded tutor
|
|
172
|
+
* (`buiTutorAsk`) answers from the lesson content. This keeps a working tutor
|
|
173
|
+
* on every course without per-course setup.
|
|
174
|
+
*/
|
|
175
|
+
export type BuiTutorMode = 'teacher' | 'native';
|
|
176
|
+
/**
|
|
177
|
+
* Resolves the tutor mode through the learner-scoped `buiMyCourseAssistantTarget`
|
|
178
|
+
* query: it returns the course only when an enabled binding exists and fails
|
|
179
|
+
* with FAILED_PRECONDITION otherwise. Any failure resolves to `native`, because
|
|
180
|
+
* the native tutor enforces its own access checks and needs no binding.
|
|
181
|
+
*/
|
|
182
|
+
export declare const useBuiTutorMode: (enrollmentId: string | undefined) => import('@tanstack/react-query').UseQueryResult<BuiTutorMode, Error>;
|
|
167
183
|
/**
|
|
168
184
|
* The calling learner's own tutor sessions for a lesson (Type-C self-scoped
|
|
169
185
|
* query — no `learnerId` arg on the wire; identity comes from the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBuildmyiqApi.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuildmyiqApi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAA0B,KAAK,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAChG,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EACT,cAAc,EACd,eAAe,EACf,SAAS,EACT,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACd,2BAA2B,EAE5B,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"useBuildmyiqApi.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuildmyiqApi.ts"],"names":[],"mappings":"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"}
|