inline-chat-kit 0.54.3 → 0.55.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/CHANGELOG.md +71 -0
- package/dist/ChatExperience/ChatExperience.d.ts +115 -0
- package/dist/ChatExperience-C2UXwrrI.js +5844 -0
- package/dist/ChatExperience-C2UXwrrI.js.map +1 -0
- package/dist/demo/ChatExperienceDemo.d.ts +27 -0
- package/dist/demo/InlineChatBanner.d.ts +6 -0
- package/dist/demo/IntroLanding.d.ts +43 -0
- package/dist/demo/featureStatus.d.ts +18 -0
- package/dist/demo/index.d.ts +8 -0
- package/dist/demo/scriptedApi.d.ts +49 -0
- package/dist/demo.js +693 -0
- package/dist/demo.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/inline-chat-kit.css +1 -1
- package/dist/inline-chat-kit.js +8 -5541
- package/dist/inline-chat-kit.js.map +1 -1
- package/dist/theme/useThemeAttribute.d.ts +16 -0
- package/getting-started.md +33 -69
- package/package.json +7 -3
package/dist/demo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","names":[],"sources":["../src/demo/InlineChatBanner.module.css","../src/demo/InlineChatBanner.tsx","../src/demo/featureStatus.ts","../src/demo/IntroLanding.module.css","../src/demo/IntroLanding.tsx","../src/demo/scriptedApi.ts","../src/demo/ChatExperienceDemo.module.css","../src/demo/ChatExperienceDemo.tsx"],"sourcesContent":["/* The demo's own banner, on the kit's tokens.\n It is a consumer of the package, so it reads `--ick-` custom properties\n the way any application would — which also means it follows the theme\n without carrying a second palette of its own. */\n\n.banner {\n display: flex;\n flex-direction: column;\n gap: var(--ick-space-2);\n width: 100%;\n max-width: 540px;\n box-sizing: border-box;\n padding: var(--ick-space-5) var(--ick-space-4) var(--ick-space-4);\n border-radius: var(--ick-radius-xl);\n background-color: var(--ick-surface-sunken);\n font-size: var(--ick-text-sm);\n line-height: 16px;\n}\n\n.header {\n display: flex;\n align-items: flex-start;\n gap: var(--ick-space-4);\n padding-inline: var(--ick-space-2);\n padding-bottom: var(--ick-space-4);\n}\n\n.headerIcon {\n flex-shrink: 0;\n margin-top: 1px;\n color: var(--ick-ink);\n}\n\n.headerText {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1;\n}\n\n.title {\n font-family: var(--ick-font-mono);\n font-size: var(--ick-text-sm);\n line-height: 16px;\n letter-spacing: -0.02em;\n color: var(--ick-ink);\n}\n\n.body {\n font-family: var(--ick-font-sans);\n font-size: var(--ick-text-sm);\n line-height: 18px;\n color: var(--ick-ink-soft);\n}\n\n.columns {\n /* A grid rather than three equal flex columns: the three groups are not the\n same length and never will be — \"Works\" is the whole component and the\n other two are what is left. Equal widths wrapped its longest item onto a\n second line while two thirds of the card sat empty. */\n display: grid;\n /* Sized to their contents, with the slack going to the gaps between them.\n Shares do not work here: the three groups have very different longest\n items, so any fixed ratio wraps one of them — equal columns broke\n \"Approve or deny a tool call\" and 2fr/1fr/1fr broke \"A composer fixed at\n the bottom\". */\n grid-template-columns: repeat(3, auto);\n justify-content: space-between;\n align-items: start;\n background-color: var(--ick-surface);\n border-radius: var(--ick-radius-lg);\n padding: var(--ick-space-4) 20px;\n gap: var(--ick-space-2);\n}\n\n.divider {\n width: 1px;\n background-color: var(--ick-border);\n flex-shrink: 0;\n margin: var(--ick-space-4) 0;\n}\n\n.column {\n display: flex;\n flex-direction: column;\n gap: var(--ick-space-2);\n padding: var(--ick-space-4);\n min-width: 0;\n}\n\n/* Flows into as many columns as fit at 150px, so a two-item list stays one\n column and a fifteen-item list becomes two or three. `break-inside` because\n a wrapped item split across a column break reads as two entries. */\n.items {\n /* The column's `gap` cannot reach inside a multi-column box. */\n line-height: 1.9;\n columns: 150px auto;\n column-gap: var(--ick-space-5);\n}\n\n.items > .item {\n display: block;\n break-inside: avoid;\n}\n\n.columnLabel {\n font-family: var(--ick-font-mono);\n font-size: var(--ick-text-sm);\n line-height: 150%;\n color: var(--ick-ink-faint);\n}\n\n.item {\n font-family: var(--ick-font-sans);\n font-size: var(--ick-text-sm);\n line-height: 16px;\n color: var(--ick-ink-soft);\n}\n\n@media (max-width: 540px) {\n .columns {\n grid-template-columns: 1fr;\n padding: var(--ick-space-2) 20px;\n }\n\n .divider {\n width: auto;\n height: 1px;\n margin: 0 var(--ick-space-4);\n }\n}\n","import type { InlineChatFeatureStatus } from \"./featureStatus\";\nimport styles from \"./InlineChatBanner.module.css\";\n\ninterface InlineChatBannerProps {\n status: InlineChatFeatureStatus;\n}\n\nexport function InlineChatBanner({ status }: InlineChatBannerProps) {\n return (\n <div className={styles.banner}>\n <div className={styles.header}>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={styles.headerIcon}\n aria-hidden\n >\n {/* currentColor, so the icon cannot drift from the text beside it */}\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" strokeWidth=\"1.2\" />\n <path d=\"M8 7v4\" stroke=\"currentColor\" strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"5\" r=\"0.8\" fill=\"currentColor\" />\n </svg>\n <div className={styles.headerText}>\n <span className={styles.title}>Quick heads up</span>\n <span className={styles.body}>\n The answers are scripted — there is no model behind this page. Everything else is\n the real component, so the list below is what you can actually try.\n </span>\n </div>\n </div>\n\n <div className={styles.columns}>\n <Column label=\"Works\" items={status.works} />\n <Column label=\"Not working\" items={status.notWorking} />\n <Column label=\"Soon\" items={status.soon} />\n </div>\n </div>\n );\n}\n\nfunction Column({ label, items }: { label: string; items: string[] }) {\n return (\n <div className={styles.column}>\n <span className={styles.columnLabel}>{label}</span>\n {/* The items get a box of their own so a long list can flow into two\n sub-columns. \"Works\" is fifteen lines and the other two are two and\n four; without this the card is mostly empty space to the right of a\n single tall list. */}\n <div className={styles.items}>\n {items.map((item) => (\n <span key={item} className={styles.item}>\n {item}\n </span>\n ))}\n </div>\n </div>\n );\n}\n","export interface InlineChatFeatureStatus {\n works: string[];\n notWorking: string[];\n soon: string[];\n}\n\n/**\n * What this demo can actually do, checked rather than remembered.\n *\n * It had drifted in both directions at once: threads sat under \"Soon\" while\n * working, and copy sat under \"Not working\" while putting 434 characters on\n * the clipboard. A list nobody trusts is worse than no list, because the one\n * thing it is for is telling a visitor what to try.\n *\n * Everything under `works` was driven in a browser before it was written here.\n * Everything under `notWorking` is simulated on purpose — this page has no\n * model behind it and says so above. `soon` is tier I of the roadmap.\n */\nexport const INLINE_CHAT_FEATURE_STATUS: InlineChatFeatureStatus = {\n works: [\n \"Send, stop, edit\",\n \"Multiline input\",\n \"Attach an image\",\n \"Dictate a message\",\n \"Copy an answer\",\n \"Rate an answer\",\n \"Regenerate and compare\",\n \"Highlight a passage\",\n \"Reply in a thread\",\n \"Answer questions inline\",\n \"Approve a tool call\",\n \"Open a plan in a pane\",\n \"Reasoning and tools\",\n \"Sources and citations\",\n \"Light and dark\",\n ],\n notWorking: [\n \"Real model answers\",\n \"Real speech to text\",\n ],\n soon: [\n \"Mobile\",\n \"A fixed composer\",\n \"Queue a message\",\n \"Saved conversations\",\n ],\n};\n","/* `min-height` and a scroll, not a fixed height and `overflow: hidden`.\n\n On a desktop the intro fits in a screen and centres in it, which is what\n the fixed height was for. On a 375x812 phone it does not: the feature\n banner alone is taller than the viewport, so `overflow: hidden` cut the\n page off just under it and **`Start experience` could not be reached at\n all** — the one control the page exists for, below a fold that would not\n move.\n\n A minimum height still centres it wherever it fits, and lets it scroll\n wherever it does not. `padding-block` so the first and last thing on the\n page are not against the edges once it is scrolling, and the safe-area\n insets on top of that for a notch. */\n.page {\n min-height: 100vh;\n min-height: 100dvh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding-block: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-bottom));\n box-sizing: border-box;\n background-color: var(--ick-page);\n overflow-x: clip;\n}\n\n.container {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 48px;\n width: 100%;\n padding: 0 24px;\n box-sizing: border-box;\n}\n\n.infoContainer {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n}\n\n\n.content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n width: 100%;\n max-width: 540px;\n}\n\n.introContent {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n}\n\n.nameContent {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n.welcome {\n font-family: var(--ick-font-mono);\n font-size: 15px;\n font-weight: 400;\n line-height: 18px;\n letter-spacing: -0.02em;\n color: var(--ick-ink);\n}\n\n.title {\n font-family: var(--ick-font-mono);\n font-size: 20px;\n font-weight: 500;\n line-height: 24px;\n letter-spacing: -0.02em;\n color: var(--ick-ink);\n text-align: center;\n}\n\n.version {\n font-family: var(--ick-font-mono);\n font-size: 12px;\n font-weight: 400;\n line-height: 16px;\n letter-spacing: -0.02em;\n color: var(--ick-ink-soft);\n}\n\n.description {\n font-family: var(--ick-font-sans);\n font-size: 14px;\n font-weight: 400;\n line-height: 18px;\n color: var(--ick-ink-soft);\n text-align: center;\n width: 100%;\n margin: 0;\n}\n\n.inputSection {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n}\n\n.bannerWrapper {\n display: flex;\n justify-content: center;\n width: 100%;\n}\n\n.buttonWrapper {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n}\n\n/* The \"desktop only\" notice that used to stand here is gone, and so is the\n media query that hid the real page behind it. Mobile is the thing being\n built now, not the thing being apologised for — and the feature banner\n below already says, honestly and in one place, what works and what does\n not. A second notice saying \"not yet\" beside it was the drift. */\n\n.fyi {\n font-family: var(--ick-font-sans);\n font-size: 10px;\n font-weight: 400;\n line-height: 15px;\n color: var(--ick-ink-faint);\n text-align: center;\n margin: 0;\n}\n\n/* The way back out, styled here rather than by whoever passes it.\n\n It used to be a `.secondaryBtn` class defined in each host's own stylesheet,\n which is two definitions of one button and a third waiting for the next host\n — and on the website the class sat in the chat page's stylesheet, so the\n link on the *intro* was styled by a file about the conversation. Targeting\n the element means a host hands over an `<a>`, or a framework's `<Link>`,\n which renders one, and gets the look without being told a class name. */\n.buttonWrapper a {\n all: unset;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 8px 16px;\n border-radius: 99px;\n font-family: var(--ick-font-mono);\n font-size: var(--ick-text-xs);\n color: var(--ick-ink-soft);\n background: transparent;\n transition: background 0.2s, color 0.2s;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .buttonWrapper a:hover {\n background: var(--ick-surface-active);\n color: var(--ick-ink);\n }\n}\n\n.buttonWrapper a:focus-visible {\n outline: 2px solid var(--ick-focus-ring);\n outline-offset: 2px;\n}\n","import { type ReactNode } from \"react\";\nimport { motion, type Variants } from \"motion/react\";\nimport { Button } from \"../Button/Button\";\nimport { InlineChatBanner } from \"./InlineChatBanner\";\nimport { INLINE_CHAT_FEATURE_STATUS } from \"./featureStatus\";\nimport styles from \"./IntroLanding.module.css\";\n\n/**\n * The page in front of the demo: what this is, what works, and a way in.\n *\n * Two copies of it before this, in the playground and on the website, along\n * with two copies of its stylesheet. The stylesheet is the reason it is worth\n * moving rather than leaving: it reached for `--color-bg-page`,\n * `--font-geist-sans` and `--font-jetbrains-mono`, none of which the kit\n * defines — so it rendered correctly only in a host that happened to have\n * them, and silently fell back to a serif on a white page in one that did\n * not. It is on `--ick-` tokens now, which the kit ships.\n *\n * What a host still gives it: the logo, and where \"back\" goes. Its identity.\n */\n\n/** How the intro arrives, and how it leaves for the chat. Exposed so a tuning\n panel can reach it; every number has a default that works. */\nexport interface IntroMotion {\n staggerIn?: number;\n stiffness?: number;\n damping?: number;\n offsetIn?: number;\n blurIn?: number;\n staggerOut?: number;\n durationOut?: number;\n offsetOut?: number;\n blurOut?: number;\n}\n\nexport interface IntroLandingProps {\n /** The host's mark. Nothing is drawn in its place if it is left off. */\n logo?: ReactNode;\n /** The way back out, rendered as given — an `<a>`, a framework `<Link>`. */\n back?: ReactNode;\n onStart: () => void;\n welcome?: string;\n title?: string;\n version?: string;\n description?: string;\n /** What the demo can actually do. Defaults to the kit's own list. */\n status?: typeof INLINE_CHAT_FEATURE_STATUS;\n motionConfig?: IntroMotion;\n}\n\nconst DEFAULTS: Required<IntroMotion> = {\n staggerIn: 0.07,\n stiffness: 100,\n damping: 36,\n offsetIn: -10,\n blurIn: 10,\n staggerOut: 0.07,\n durationOut: 0.28,\n offsetOut: -10,\n blurOut: 10,\n};\n\nexport function IntroLanding({\n logo,\n back,\n onStart,\n welcome = \"Welcome\",\n title = \"This is inline chat experience\",\n version = \"v1.0.0\",\n description = \"Exploration of having the input be the same as response. Or better said input morphing into chat bubble and maintains the continuous experience.\",\n status = INLINE_CHAT_FEATURE_STATUS,\n motionConfig,\n}: IntroLandingProps) {\n const m = { ...DEFAULTS, ...motionConfig };\n\n const container: Variants = {\n hidden: {},\n visible: { transition: { staggerChildren: m.staggerIn } },\n exit: { transition: { staggerChildren: m.staggerOut, staggerDirection: -1 as const } },\n };\n\n const item: Variants = {\n hidden: { opacity: 0, filter: `blur(${m.blurIn}px)`, y: m.offsetIn },\n visible: {\n opacity: 1,\n filter: \"blur(0px)\",\n y: 0,\n transition: { type: \"spring\", stiffness: m.stiffness, damping: m.damping },\n },\n exit: {\n opacity: 0,\n filter: `blur(${m.blurOut}px)`,\n y: m.offsetOut,\n transition: { duration: m.durationOut, ease: [0.4, 0, 1, 1] as const },\n },\n };\n\n return (\n <motion.div\n key=\"intro\"\n className={styles.page}\n variants={container}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n >\n <div className={styles.container}>\n <div className={styles.infoContainer}>\n {logo && <motion.div variants={item}>{logo}</motion.div>}\n <div className={styles.content}>\n <div className={styles.introContent}>\n <motion.div className={styles.nameContent} variants={item}>\n <span className={styles.welcome}>{welcome}</span>\n <span className={styles.title}>{title}</span>\n </motion.div>\n <motion.span className={styles.version} variants={item}>\n {version}\n </motion.span>\n </div>\n <motion.p className={styles.description} variants={item}>\n {description}\n </motion.p>\n </div>\n </div>\n\n <motion.div variants={item} className={styles.bannerWrapper}>\n <InlineChatBanner status={status} />\n </motion.div>\n\n {/* Three empty slots, so the button waits three beats rather than\n arriving with the paragraph above it. A `delay` would do the same\n thing and then drift the moment the stagger changes; these move\n with it. */}\n <motion.div variants={item} style={{ display: \"none\" }} />\n <motion.div variants={item} style={{ display: \"none\" }} />\n <motion.div variants={item} style={{ display: \"none\" }} />\n\n <motion.div variants={item} className={styles.buttonWrapper}>\n <Button variant=\"glass\" size=\"m\" onClick={onStart}>\n Start experience\n </Button>\n {back}\n </motion.div>\n </div>\n </motion.div>\n );\n}\n","import type { Attachment, Question, Source, TurnPart, TurnPartUpdate } from \"../index\";\n\n/**\n * The demo pretending to be a model, and now pretending to be an agent.\n *\n * A `SendHandler` may stream two kinds of thing: strings, which are deltas of\n * the answer's prose, and `TurnPartUpdate`s, which are merged into the turn by\n * id — an update rather than a whole part, because a stream's second word\n * about a thing should be able to be only what changed.\n * Everything the agent tier draws arrives through the second kind — so this is\n * where reasoning, tool calls, a plan and a question get into the conversation\n * at all, rather than only into Storybook.\n *\n * Routed on what was typed, so each one is reachable by asking for it. The\n * openers on the empty state are the four that route somewhere.\n */\n\n/* Markdown, because that is what a model returns. The first and last\n paragraphs are left as plain prose on purpose: the showcase recording draws\n a marker from \"Higgs\" to \"2012\", and a stroke has to cross the boundary of\n a `**bold**` run to prove that it can. */\n/* Regenerating asks for *another* attempt, so the demo has to have another\n one — two identical answers behind a \"1 / 2\" control teaches the wrong\n thing about what the control is for. Counted per turn, because that is what\n regenerating is: the same turn, answered again. */\nconst attempts = new Map<string, number>();\n\nconst AI_RESPONSE = [\n \"Particle physics studies the most fundamental constituents of matter and the forces that act between them.\",\n \"The **Standard Model** organises them into three families:\",\n \"- twelve fermions — six quarks and six leptons\\n- the force-carrying bosons\\n- the Higgs, which gives the rest their mass\",\n \"The Higgs boson, found at CERN in 2012, completes the picture by giving elementary particles their mass through interaction with the Higgs field.\",\n];\n\nconst HIGGS_RESPONSE = [\n \"The Higgs boson is a *point particle* — it has no measurable spatial extent at any scale we can currently probe.\",\n \"| property | value |\\n| --- | --- |\\n| mass | ~125 GeV/c² |\\n| charge | 0 |\\n| spin | 0 |\",\n \"So 'how big is it' has only one honest answer: it has no size, only `mass` and quantum numbers.\",\n];\n\nconst PLAN_RESPONSE = [\n \"Here is what I would do, in order. The first two are cheap and tell us whether the rest is worth doing.\",\n];\n\n/* `[^1]` is the kit's citation marker. The number is a position in the turn's\n `sources` part, which is why that part is sent before the prose that cites\n it. Written the way a model writes it — mid-sentence, after the claim it\n supports, not gathered at the end. */\nconst CITED_RESPONSE = [\n \"The current combined figure is **125.25 GeV/c²**[^1], from ATLAS and CMS together — separately, neither experiment gets there.\",\n \"It is known to about a fifth of a percent[^2], which for a particle discovered in 2012 is a remarkably tight number.\",\n \"The uncertainty is now dominated by systematics rather than statistics[^3] — more collisions alone will not sharpen it much further.\",\n];\n\nconst SOURCES: Source[] = [\n {\n id: \"atlas-cms\",\n title: \"Combined measurement of the Higgs boson mass\",\n origin: \"atlas.cern\",\n url: \"https://example.com/atlas-cms\",\n quote: \"125.25 ± 0.17 GeV, from the combination of the ATLAS and CMS datasets.\",\n },\n {\n id: \"pdg\",\n title: \"Particle Data Group — Higgs boson listings\",\n origin: \"pdg.lbl.gov\",\n url: \"https://example.com/pdg\",\n },\n {\n id: \"systematics\",\n title: \"Systematic uncertainties in the mass measurement\",\n origin: \"cms.cern\",\n url: \"https://example.com/systematics\",\n },\n];\n\nconst THOUGHTS = [\n {\n id: \"read\",\n label: \"Read what is being asked\",\n body: \"Not the mass itself — how well it is known, and by whom.\",\n },\n {\n id: \"split\",\n label: \"Separate the two numbers\",\n body: \"The value and its uncertainty come from different arguments; giving one without the other answers half.\",\n },\n {\n id: \"check\",\n label: \"Check which is the limiting one now\",\n body: \"Statistics used to dominate. It is systematics now, and that changes what more data would buy.\",\n },\n];\n\n/**\n * Three questions, one of each type, about the experiment the rest of this\n * demo is about.\n *\n * They used to be about arranging care for somebody — carried over from\n * another product, and the one thing in a chat headed \"ask me about particle\n * physics\" that had nothing to do with it. A demo that changes subject\n * halfway is a demo somebody has to explain.\n */\nexport const QUESTIONS: Question[] = [\n {\n id: \"setup\",\n type: \"inputs\",\n title: \"What are we running?\",\n subtitle: \"Enough to set the geometry up — the rest I can assume\",\n shortTitle: \"The setup\",\n fields: [\n { id: \"particle\", label: \"Particle\", placeholder: \"Electron\" },\n { id: \"separation\", label: \"Slit separation\", placeholder: \"100 nm\" },\n ],\n },\n {\n id: \"detector\",\n type: \"single\",\n title: \"Where do you put the detector?\",\n subtitle: \"This is the experiment, really — the rest is apparatus\",\n shortTitle: \"Detector\",\n options: [\n {\n id: \"slits\",\n title: \"At the slits\",\n description: \"Learn which path each particle took\",\n short: \"At the slits\",\n },\n {\n id: \"screen\",\n title: \"At the screen\",\n description: \"Learn only where each one landed\",\n short: \"At the screen\",\n },\n {\n id: \"nowhere\",\n title: \"Nowhere\",\n description: \"Let it run unobserved and see what arrives\",\n short: \"Nowhere\",\n },\n ],\n },\n {\n id: \"plots\",\n type: \"multi\",\n title: \"What should I plot?\",\n subtitle: \"Pick everything worth looking at\",\n shortTitle: \"Plots\",\n allowOther: true,\n allowEmpty: true,\n options: [\n {\n id: \"fringes\",\n title: \"Interference pattern\",\n description: \"Counts across the screen\",\n short: \"Fringes\",\n },\n {\n id: \"psi\",\n title: \"Wavefunction\",\n description: \"|ψ|² as it evolves\",\n short: \"|ψ|²\",\n },\n {\n id: \"path\",\n title: \"Which-path record\",\n description: \"Only meaningful with a detector at the slits\",\n short: \"Which-path\",\n },\n ],\n },\n];\n\nconst wait = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\n/** Word by word, which exercises the streaming path rather than the easy one. */\nasync function* prose(blocks: string[]): AsyncGenerator<string> {\n // Joined as blocks, not sentences: markdown needs the blank line between a\n // paragraph and the list that follows it.\n for (const word of blocks.join(\"\\n\\n\").split(/(\\s+)/)) {\n await wait(24);\n yield word;\n }\n}\n\n/**\n * Thinking, streamed a sentence at a time, then folded away.\n *\n * The same id throughout: the first send carries the text, the last carries\n * only the state, and the merge keeps everything in between.\n */\nasync function* thinking(id: string, sentences: string[]): AsyncGenerator<TurnPart> {\n let text = \"\";\n for (const sentence of sentences) {\n text += (text ? \"\\n\\n\" : \"\") + sentence;\n yield { kind: \"reasoning\", id, text, state: \"thinking\" };\n await wait(420);\n }\n yield { kind: \"reasoning\", id, state: \"done\" };\n}\n\nconst SEARCH_INPUT = { query: \"higgs boson mass measurement\", limit: 3 };\nconst SEARCH_OUTPUT = {\n results: [\n { title: \"ATLAS and CMS combined measurement\", url: \"https://example.com/atlas-cms\", rank: 1 },\n { title: \"Particle Data Group — Higgs boson\", url: \"https://example.com/pdg\", rank: 2 },\n ],\n took_ms: 412,\n};\n\nasync function* toolCall(id: string): AsyncGenerator<TurnPart> {\n yield { kind: \"tool\", id, name: \"search_web\", state: \"running\", summary: \"Searching the web\", input: SEARCH_INPUT };\n await wait(900);\n yield { kind: \"tool\", id, name: \"search_web\", state: \"done\", summary: \"2 results\", output: SEARCH_OUTPUT, duration: 412 };\n}\n\nconst PLAN = [\n { id: \"read\", label: \"Read the care plan\" },\n { id: \"meds\", label: \"Check the medication list against the prescription\" },\n { id: \"gaps\", label: \"Find the gaps in the weekly cover\" },\n { id: \"draft\", label: \"Draft the questions for the family\" },\n];\n\n/** Work moving down the list, one row at a time. */\nasync function* plan(id: string): AsyncGenerator<TurnPart> {\n for (let at = 0; at <= PLAN.length; at++) {\n yield {\n kind: \"tasks\",\n id,\n title: \"Plan\",\n collapsible: true,\n tasks: PLAN.map((task, i) => ({\n ...task,\n state: i < at ? (\"done\" as const) : i === at ? (\"running\" as const) : (\"pending\" as const),\n })),\n };\n await wait(800);\n }\n}\n\n/** Steps arriving one at a time, each finishing before the next appears. */\nasync function* chain(id: string): AsyncGenerator<TurnPart> {\n for (let at = 0; at < THOUGHTS.length; at++) {\n yield {\n kind: \"chain\",\n id,\n state: \"thinking\",\n steps: THOUGHTS.slice(0, at + 1).map((step, i) => ({\n ...step,\n state: i < at ? (\"done\" as const) : (\"running\" as const),\n })),\n };\n await wait(700);\n }\n yield {\n kind: \"chain\",\n id,\n state: \"done\",\n steps: THOUGHTS.map((step) => ({ ...step, state: \"done\" as const })),\n };\n}\n\nconst asks = (message: string, ...words: string[]) => {\n const said = message.toLowerCase();\n return words.some((word) => said.includes(word));\n};\n\n/**\n * Where a real app would call its model.\n *\n * The kit owns the turn state, the streaming and the reveal; everything here\n * is the demo pretending to be an API, so the playground costs nothing to run.\n */\nconst LOOKED = [\n \"I can see it. Whatever you send along with a message arrives here the same way the text does — one `attachments` array on the turn, and the composer that held it is the same one that shows it afterwards.\",\n \"This demo does not read the picture; there is no model behind it. A real one would get the file and the sentence in the same request.\",\n];\n\nconst AGAIN = [\n [\n \"Another way to put it: particle physics is the study of what is left when you stop dividing.\",\n \"Everything in the Standard Model is there because dividing it further stopped producing anything smaller — twelve fermions, the bosons that carry the forces between them, and the Higgs.\",\n \"The interesting part is not the list. It is that the list is *short*, and that nothing found since 1973 has needed adding to it.\",\n ],\n [\n \"Once more, from the other end. Start with the four forces and ask what carries each one.\",\n \"Electromagnetism has the photon. The strong force has gluons. The weak force has the W and Z. Gravity has no entry here at all — which is the honest shape of the field's biggest open problem.\",\n \"Matter is what those forces act on: quarks, which feel the strong force, and leptons, which do not.\",\n ],\n];\n\n/**\n * A plan, written out. The demo's artifact.\n *\n * Long enough that pouring it into the answer would bury the answer, which is\n * the whole argument for a pane: the card in the transcript is a window and\n * this is what is behind it.\n */\nexport const RUNNING_PLAN = `Week 1 — base\nMon rest\nTue 4 km easy, conversational pace\nWed cross-train, 30 min\nThu 5 × 400 m at 5k effort, 90 s jog between\nFri rest\nSat 6 km easy\nSun 20 min walk\n\nWeek 2 — base\nMon rest\nTue 5 km easy\nWed cross-train, 35 min\nThu 6 × 400 m, 90 s jog between\nFri rest\nSat 7 km easy, last kilometre at pace\nSun 20 min walk\n\nWeek 3 — build\nMon rest\nTue 5 km easy\nWed cross-train, 35 min\nThu 4 × 800 m at 5k effort, 2 min jog between\nFri rest\nSat 8 km easy\nSun 20 min walk\n\nWeek 4 — cut back\nMon rest\nTue 4 km easy\nWed cross-train, 30 min\nThu 5 × 400 m, 90 s jog between\nFri rest\nSat 5 km easy\nSun rest\n\nWeek 5 — build\nMon rest\nTue 6 km easy\nWed cross-train, 40 min\nThu 5 × 800 m, 2 min jog between\nFri rest\nSat 9 km easy\nSun 20 min walk\n\nWeek 6 — sharpen\nMon rest\nTue 6 km with 3 km at target pace\nWed cross-train, 30 min\nThu 8 × 400 m, 60 s jog between\nFri rest\nSat 8 km easy\nSun 20 min walk\n\nWeek 7 — sharpen\nMon rest\nTue 5 km with 4 km at target pace\nWed cross-train, 30 min\nThu 6 × 400 m, 60 s jog between\nFri rest\nSat 6 km easy\nSun rest\n\nWeek 8 — taper and race\nMon rest\nTue 4 km easy with 4 × 100 m strides\nWed rest\nThu 3 km easy\nFri rest\nSat race, 5 km\nSun 20 min walk\n\nNotes\nEasy means you can hold a conversation. If you cannot, it is not easy.\nEvery hard day is followed by a rest day; that is where the fitness is made.\nMiss a week and repeat it rather than skipping ahead to catch up.`;\n\nexport async function* scriptedApi(\n message: string,\n { attachments, turnId }: { attachments: Attachment[]; turnId: string }\n): AsyncGenerator<string | TurnPartUpdate> {\n /* Before the routing on words: something was sent along, and that is what\n the answer should be about. */\n if (attachments.length > 0) {\n yield* thinking(\"r\", [\n `${attachments.length === 1 ? \"A file\" : `${attachments.length} files`} came with this.`,\n \"Say what arrived, and be honest that nothing here is looking at it.\",\n ]);\n yield* prose(LOOKED);\n return;\n }\n\n /* What a pane is for: something the answer produced that is bigger than the\n answer. The card arrives before the content, which is how one really\n arrives — the title first, shimmering, then the plan behind it. */\n if (asks(message, \"plan\", \"training\", \"5k\", \"run \", \"running\", \"trening\", \"trčanj\", \"trcanj\")) {\n yield* thinking(\"r\", [\n \"Eight weeks is the shortest honest 5k build for somebody starting from a base.\",\n \"The plan is long. Put it behind a card rather than into the answer — an answer nobody can read past is not an answer.\",\n ]);\n yield { kind: \"artifact\", id: \"plan\", title: \"5k training plan\", state: \"writing\" };\n yield \"Here is an eight-week plan. Four sessions a week, one of them hard, and a cut-back week in the middle so the fourth week does not become the one you quit in.\";\n await wait(900);\n yield {\n kind: \"artifact\",\n id: \"plan\",\n meta: \"8 weeks · 4 sessions a week\",\n preview: \"text\",\n content: RUNNING_PLAN,\n state: \"done\",\n };\n yield \" Open it to see the weeks.\";\n return;\n }\n\n if (asks(message, \"question\", \"ask me\", \"set up\", \"double-slit\", \"experiment\", \"pitanj\")) {\n yield* thinking(\"r\", [\n \"They want to be asked rather than to specify the whole thing up front.\",\n \"Three is the most anybody answers in one sitting: the geometry, then where the detector goes — which is the only choice that changes the physics — then what to plot.\",\n ]);\n yield {\n kind: \"question\",\n id: \"q\",\n title: \"Setting up the run\",\n questions: QUESTIONS,\n answers: {},\n activeIndex: 0,\n };\n return;\n }\n\n if (asks(message, \"delete\", \"run \", \"send an email\", \"permission\", \"approve\")) {\n yield* thinking(\"r\", [\n \"This one changes something outside the conversation, so it is not mine to decide.\",\n \"Show what it would run, and wait.\",\n ]);\n yield {\n kind: \"approval\",\n id: \"ask\",\n title: \"Run a command in your shell\",\n description: \"It removes the generated screenshots. Nothing else is touched.\",\n tool: { name: \"bash\", input: { command: \"rm -rf Shots/\", cwd: \"~/Projects/chat\" } },\n };\n return;\n }\n\n if (asks(message, \"plan\", \"todo\", \"steps\", \"what would you do\")) {\n yield* thinking(\"r\", [\n \"This is a sequence, not a single answer, so the plan is the answer.\",\n \"Order it so the cheap checks come first — if the medication list already matches, the rest is much smaller.\",\n ]);\n yield* plan(\"p\");\n yield* prose(PLAN_RESPONSE);\n return;\n }\n\n /* Before the mass branch, which shares a word with it — asking to show the\n working is a different request from asking for the number. */\n if (asks(message, \"sources\", \"cite\", \"how do you know\", \"izvor\")) {\n yield* chain(\"c\");\n /* The list first, so a `[^1]` in the prose comes up already pointing at\n something. Sent after, the markers would draw bare and fill in — which\n works, and looks like a bug. */\n yield { kind: \"sources\", id: \"s\", sources: SOURCES, title: \"Sources\", collapsible: true };\n yield* prose(CITED_RESPONSE);\n return;\n }\n\n if (asks(message, \"how big\", \"mass\", \"size\", \"weigh\")) {\n yield* thinking(\"r\", [\n \"The question is about the Higgs boson's size, and the honest answer is that it does not have one.\",\n \"Better to give the mass instead, and say why size is the wrong question — but check the current figure first.\",\n ]);\n yield* toolCall(\"t\");\n yield* prose(HIGGS_RESPONSE);\n return;\n }\n\n /* The general answer, and a different one each time it is asked again. */\n const attempt = (attempts.get(turnId) ?? 0) % (AGAIN.length + 1);\n attempts.set(turnId, attempt + 1);\n\n if (attempt > 0) {\n yield* thinking(\"r\", [\n \"Asked again, so the first answer did not land.\",\n \"Same physics, different way in — repeating it in other words is not answering it again.\",\n ]);\n yield* prose(AGAIN[attempt - 1]);\n return;\n }\n\n yield* thinking(\"r\", [\n \"A general question, so the answer should start from what the field is for rather than from a definition.\",\n \"Three families is the useful shape: fermions, bosons, and the Higgs.\",\n ]);\n yield* prose(AI_RESPONSE);\n}\n\n/**\n * A reply inside a thread on a passage.\n *\n * Prose only. A thread is a follow-up on something already said, and a tool\n * call inside a popover over the answer would be absurd.\n */\nexport async function* threadReply(): AsyncGenerator<string> {\n yield* prose([\n \"Marking a passage and asking about it keeps the question attached to what it is about — so the answer can be short.\",\n \"That is the whole of the thread: the quote, one question, one answer.\",\n ]);\n}\n\n/**\n * A transcript, without a transcriber.\n *\n * The kit records for real — permission, `MediaRecorder`, the level ring all\n * come from the microphone — and then hands the audio here, where there is\n * nowhere to send it. This demo has no backend and the browser's own\n * `SpeechRecognition` cannot be reached through `onTranscribe`, because it\n * insists on holding the microphone itself rather than taking a recording.\n *\n * So the words are scripted, like every other answer in this demo, and the\n * feature list says so. Everything around them is not: refuse the permission\n * prompt and the refusal is real, talk louder and the ring is reading your\n * room, press stop halfway and the abort signal fires.\n *\n * A real handler is this shape with a `fetch` in it.\n */\nexport async function* scriptedTranscript(\n audio: Blob,\n { signal }: { signal: AbortSignal }\n): AsyncGenerator<string> {\n const seconds = Math.max(1, Math.round(audio.size / 12000));\n const words = `this is a scripted transcript standing in for about ${seconds} seconds of speech`.split(\" \");\n for (const word of words) {\n await new Promise((done) => setTimeout(done, 90));\n if (signal.aborted) return;\n yield `${word} `;\n }\n}\n","/* The plan inside the artifact pane. The kit draws the pane; what is in it is\n the host's, and here the host is this demo — so its typography lives beside\n the demo rather than in a page's stylesheet. */\n.plan {\n margin: 0;\n font-family: var(--ick-font-sans);\n font-size: var(--ick-text-sm);\n line-height: 1.65;\n color: var(--ick-ink-soft);\n white-space: pre-wrap;\n}\n","import { useCallback, useRef, useState, type ReactNode } from \"react\";\nimport { AnimatePresence } from \"motion/react\";\nimport { ChatExperience, type PartWriter } from \"../ChatExperience/ChatExperience\";\nimport type { InlineAnimConfig } from \"../ChatInput/ChatInput\";\nimport type { FoldMotion } from \"../QuestionGroup/QuestionGroup\";\nimport type { Answer } from \"../QuestionCard/types\";\nimport type { Decision } from \"../Approval/Approval\";\nimport { useThemeAttribute } from \"../theme/useThemeAttribute\";\nimport { IntroLanding, type IntroMotion } from \"./IntroLanding\";\nimport { QUESTIONS, RUNNING_PLAN, scriptedApi, threadReply, scriptedTranscript } from \"./scriptedApi\";\nimport styles from \"./ChatExperienceDemo.module.css\";\n\n/**\n * The demo, whole: the landing page, the chat, and the scripted answers behind\n * it.\n *\n * It is in the published package on purpose. Two apps show this demo — the\n * playground and the website — and before this they each had their own copy of\n * all of it: 865 and 890 lines of page, 537 identical lines of scripted\n * answers, 300 of stylesheet, and a banner and a landing page each. Nothing\n * about that content is specific to either app, so neither one owned it, and a\n * change to it was a change in two places that only ever got made in one.\n *\n * A host gives it two things, and they are the two things that genuinely\n * differ: its logo, and where \"back\" goes.\n *\n * This is not the library's surface — `ChatExperience` is. It lives behind the\n * `inline-chat-kit/demo` entry point, so an app that does not import it does\n * not carry a line of it.\n */\n\n/** A small window, so the meter is worth looking at. A 200k one would sit at\n 1% all afternoon and never show what the component does when it fills. */\nconst CONTEXT_TOTAL = 8_000;\n/** What a system prompt and the tool definitions cost before anybody types. */\nconst CONTEXT_BASE = 900;\n\nexport interface ChatExperienceDemoProps {\n /** The host's mark, on the landing page. */\n logo?: ReactNode;\n /** The way back out of the landing page — an `<a>`, or a framework `<Link>`,\n which renders one. Styled by the kit; the destination is the host's. */\n back?: ReactNode;\n /** Where the header's back control goes, once you are in the chat. */\n backHref?: string;\n backLabel?: string;\n /** Start in the chat rather than on the landing page. */\n skipIntro?: boolean;\n /** The theme, if the host keeps it. Left off, the header's own toggle does. */\n theme?: \"light\" | \"dark\" | null;\n onThemeChange?: (theme: \"light\" | \"dark\") => void;\n /** Development chrome the playground turns on and nobody else does. */\n cursor?: boolean;\n /** Motion, opened up so a tuning panel can reach it. */\n animationConfig?: InlineAnimConfig;\n foldMotion?: FoldMotion;\n feedDelay?: number;\n introMotion?: IntroMotion;\n}\n\nexport function ChatExperienceDemo({\n logo,\n back,\n backHref = \"/\",\n backLabel = \"Back to home\",\n skipIntro = false,\n theme,\n onThemeChange,\n cursor = false,\n animationConfig,\n foldMotion,\n feedDelay,\n introMotion,\n}: ChatExperienceDemoProps) {\n const [started, setStarted] = useState(skipIntro);\n\n /* The landing page gets the theme too, and only when the host is the one\n holding it. `ChatExperience` writes the same attribute from the same value\n once the chat is up, so the two agree by construction — but it is not\n mounted yet while somebody is still reading the page in front of it, and\n without this that page came up in whatever the system preferred and then\n changed colour when they pressed the button.\n\n Skipped when `theme` is undefined, because then the chat holds its own and\n this would be a second writer removing what the first had just set. */\n useThemeAttribute(theme === undefined ? undefined : theme);\n\n /* The answers to a question the assistant asked.\n\n Held in a ref rather than in state, and read only inside the handler: the\n row is memoised, and a callback rebuilt on every render is what makes\n `memo` give up. Keyed by the part's id, so two questionnaires in one\n conversation do not share answers. */\n const answers = useRef<Record<string, Record<string, Answer>>>({});\n\n const onAnswerQuestion = useCallback(\n (write: PartWriter, turnId: string, partId: string, questionId: string, answer: Answer) => {\n const given = { ...(answers.current[partId] ?? {}), [questionId]: answer };\n answers.current[partId] = given;\n\n const next = QUESTIONS.findIndex((q) => q.id === questionId) + 1;\n const finished = next >= QUESTIONS.length;\n write(turnId, {\n kind: \"question\",\n id: partId,\n title: \"Setting up the run\",\n questions: QUESTIONS,\n answers: given,\n activeIndex: finished ? null : next,\n /* Once every question is answered the whole step folds to one row. */\n collapsible: finished,\n });\n },\n []\n );\n\n const onEditQuestion = useCallback(\n (write: PartWriter, turnId: string, partId: string, index: number) => {\n write(turnId, {\n kind: \"question\",\n id: partId,\n questions: QUESTIONS,\n answers: answers.current[partId] ?? {},\n activeIndex: index,\n collapsible: false,\n });\n },\n []\n );\n\n /* A decision the agent asked for. Recorded on the part it was asked on, and\n then the thing it asked about either happens or does not — which in a demo\n with no shell is one more part rather than a command. */\n const onDecideApproval = useCallback(\n (write: PartWriter, turnId: string, partId: string, decision: Decision) => {\n write(turnId, { kind: \"approval\", id: partId, decision });\n if (decision === \"denied\") return;\n\n write(turnId, {\n kind: \"tool\",\n id: `${partId}-ran`,\n name: \"bash\",\n state: \"running\",\n summary: \"Removing Shots/\",\n input: { command: \"rm -rf Shots/\" },\n });\n window.setTimeout(() => {\n write(turnId, {\n kind: \"tool\",\n id: `${partId}-ran`,\n name: \"bash\",\n state: \"done\",\n summary: \"42 files removed\",\n duration: 380,\n output: \"removed 42 files, 3 directories\",\n });\n }, 1100);\n },\n []\n );\n\n return (\n <AnimatePresence mode=\"wait\">\n {started ? (\n <ChatExperience\n key=\"chat\"\n onSend={scriptedApi}\n /* Recording is the kit's; the words are this demo's, and scripted\n like every other answer here. */\n onTranscribe={scriptedTranscript}\n onThreadReply={threadReply}\n title=\"inline chat experience\"\n backHref={backHref}\n backLabel={backLabel}\n placeholder=\"Ask me about particle physics…\"\n empty={{\n title: \"Ask me about particle physics\",\n description: \"The Standard Model, the Higgs, and what a boson actually is.\",\n /* One opener per branch of `scriptedApi`, so everything the kit can\n draw is reachable by pressing something rather than by knowing\n what to type. */\n suggestions: [\n \"What does particle physics actually study?\",\n \"How big is the Higgs boson?\",\n \"Write me a plan for running a 5k\",\n \"How do you know — show me your sources\",\n \"What would you do first — give me a plan\",\n \"Set up a double-slit experiment\",\n \"Delete the screenshots\",\n ],\n }}\n contextTotal={CONTEXT_TOTAL}\n contextBase={CONTEXT_BASE}\n /* The host's content, not the kit's. A plan here, a document or a\n table somewhere else — which is the whole reason the pane takes\n children rather than content. */\n artifact={() => ({\n title: \"5k training plan\",\n meta: \"8 weeks · 4 sessions a week\",\n children: <pre className={styles.plan}>{RUNNING_PLAN}</pre>,\n })}\n theme={theme}\n onThemeChange={onThemeChange}\n cursor={cursor}\n selectionToggle\n animationConfig={animationConfig}\n foldMotion={foldMotion}\n feedDelay={feedDelay}\n onAnswerQuestion={onAnswerQuestion}\n onEditQuestion={onEditQuestion}\n onDecideApproval={onDecideApproval}\n />\n ) : (\n <IntroLanding\n key=\"intro\"\n logo={logo}\n back={back}\n onStart={() => setStarted(true)}\n motionConfig={introMotion}\n />\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export { useVoiceInput } from './voice/useVoiceInput';
|
|
|
14
14
|
export type { TranscribeContext, TranscribeHandler, UseVoiceInputOptions, VoiceInput, VoiceState, } from './voice/useVoiceInput';
|
|
15
15
|
export { announce } from './announce/announce';
|
|
16
16
|
export type { Politeness } from './announce/announce';
|
|
17
|
+
export { ChatExperience } from './ChatExperience/ChatExperience';
|
|
18
|
+
export type { ChatExperienceProps, ChatExperienceEmpty, ChatExperienceArtifact, PartWriter, } from './ChatExperience/ChatExperience';
|
|
17
19
|
export { ChatHeader, headerIconSize } from './ChatHeader/ChatHeader';
|
|
18
20
|
export type { ChatHeaderAction, ChatHeaderProps, ChatHeaderSize, ChatHeaderVariant, } from './ChatHeader/ChatHeader';
|
|
19
21
|
export { ChatTurnRow } from './ChatTurnRow/ChatTurnRow';
|