lightnode-sdk 0.8.3 → 0.8.5
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/add.d.ts +1 -1
- package/dist/add.js +161 -53
- package/package.json +1 -1
package/dist/add.d.ts
CHANGED
|
@@ -119,7 +119,7 @@ export interface LayoutPatch {
|
|
|
119
119
|
* Returns what happened so the CLI can report it; never throws.
|
|
120
120
|
*/
|
|
121
121
|
export declare function patchLayoutWithProviders(cwd?: string): LayoutPatch;
|
|
122
|
-
export declare const SCAFFOLD_GLOBALS_CSS = "@import \"tailwindcss\";\n\n/* dark mode via .dark class (we default the app to dark) */\n@custom-variant dark (&:is(.dark, .dark *));\n\n/* design tokens (light) - ported from lcai-chat-v2 */\n:root {\n font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;\n\n --background: #ffffff;\n --primary: #6767e9;\n --primary-600: #5a4fd8;\n --foreground: #09090b;\n --card: #ffffff;\n --card-foreground: #09090b;\n --popover: #ffffff;\n --popover-foreground: hsl(240 10% 3.9%);\n --primary-foreground: #fafafa;\n --secondary: hsl(240 4.8% 95.9%);\n --secondary-foreground: hsl(240 5.9% 10%);\n --muted: hsl(240 4.8% 95.9%);\n --muted-foreground: hsl(240 3.8% 46.1%);\n --accent: hsl(240 4.8% 95.9%);\n --accent-foreground: hsl(240 5.9% 10%);\n --destructive: #ef4d6a;\n --destructive-foreground: hsl(0 0% 98%);\n --success: #15bd77;\n --warning: #eaa53d;\n --border: hsl(240 5.9% 90%);\n --input: hsl(240 5.9% 90%);\n --ring: hsl(240 10% 3.9%);\n --radius: 0.625rem;\n\n --surface-base-subtle: rgba(34, 35, 42, 0.02);\n --surface-base-faint: rgba(14, 18, 27, 0.04);\n --surface-base-light: rgba(204, 206, 239, 0.16);\n --surface-elevation-light: #ffffff;\n\n --content-primary: #0f0f14;\n --content-default: #373842;\n --content-soft: #656678;\n --content-extraLight: #9798b6;\n\n --border-soft: rgba(14, 18, 27, 0.08);\n --border-light: rgba(14, 18, 27, 0.06);\n}\n\n/* design tokens (dark) */\n.dark {\n --background: #070710;\n --foreground: hsl(0 0% 98%);\n --card: #0f0f14;\n --card-foreground: hsl(0 0% 98%);\n --popover: #0f0f14;\n --popover-foreground: hsl(0 0% 98%);\n --primary: #7064e9;\n --primary-600: #8c71f6;\n --primary-foreground: hsl(0 0% 98%);\n --secondary: hsl(240 3.7% 15.9%);\n --secondary-foreground: hsl(0 0% 98%);\n --muted: hsl(240 3.7% 15.9%);\n --muted-foreground: hsl(240 5% 64.9%);\n --accent: hsl(240 3.7% 15.9%);\n --accent-foreground: hsl(0 0% 98%);\n --destructive: #fb5a76;\n --destructive-foreground: hsl(0 0% 98%);\n --success: #22d68a;\n --warning: #f5be5c;\n --border: hsl(240 3.7% 15.9%);\n --input: hsl(240 3.7% 15.9%);\n --ring: hsl(240 4.9% 83.9%);\n\n --surface-base-subtle: rgba(204, 206, 239, 0.02);\n --surface-base-faint: rgba(204, 206, 239, 0.04);\n --surface-base-light: rgba(204, 206, 239, 0.08);\n --surface-elevation-light: #0f0f14;\n\n --content-primary: #cccef0;\n --content-default: #9798b6;\n --content-soft: rgba(154, 156, 207, 0.8);\n --content-extraLight: #9798b6;\n\n --border-soft: rgba(204, 206, 239, 0.12);\n --border-light: rgba(204, 206, 239, 0.08);\n}\n\n/* theme mapping (Tailwind v4 @theme) */\n@theme inline {\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-lg: var(--radius);\n\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-600: var(--primary-600);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-destructive-foreground: var(--destructive-foreground);\n --color-success: var(--success);\n --color-warning: var(--warning);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n\n --color-surface-base-subtle: var(--surface-base-subtle);\n --color-surface-base-faint: var(--surface-base-faint);\n --color-surface-base-light: var(--surface-base-light);\n --color-surface-elevation-light: var(--surface-elevation-light);\n --color-surface-base-brand-default: #693ee0;\n --color-surface-base-brand-strong: #8c71f6;\n\n --color-content-primary: var(--content-primary);\n --color-content-default: var(--content-default);\n --color-content-soft: var(--content-soft);\n --color-content-extraLight: var(--content-extraLight);\n\n --color-bdr-soft: var(--border-soft);\n --color-bdr-light: var(--border-light);\n\n --color-gradient-primary: linear-gradient(270deg, #7064e9 0%, #dd00ac 100%);\n}\n\n@layer base {\n * {\n border-color: var(--border);\n }\n body {\n background-color: var(--background);\n color: var(--foreground);\n overflow-x: hidden;\n }\n html {\n overflow-x: hidden;\n }\n button {\n cursor: pointer;\n }\n button:disabled {\n cursor: not-allowed;\n }\n /* visible keyboard focus across interactive elements */\n a:focus-visible,\n button:focus-visible,\n input:focus-visible,\n select:focus-visible,\n textarea:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n border-radius: 6px;\n }\n}\n\n/* respect reduced-motion: kill non-essential animation */\n@media (prefers-reduced-motion: reduce) {\n *,\n ::before,\n ::after {\n animation-duration: 0.001ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.001ms !important;\n scroll-behavior: auto !important;\n }\n}\n\n/* ambient app background (gradient mesh behind everything) */\nbody::before {\n content: \"\";\n position: fixed;\n inset: 0;\n z-index: -1;\n pointer-events: none;\n background:\n radial-gradient(60% 50% at 50% -6%, rgba(221, 0, 172, 0.10), transparent 60%),\n radial-gradient(55% 45% at 12% -8%, rgba(112, 100, 233, 0.14), transparent 60%),\n radial-gradient(50% 40% at 88% -2%, rgba(112, 100, 233, 0.12), transparent 60%),\n radial-gradient(45% 45% at 50% 115%, rgba(112, 100, 233, 0.07), transparent 60%);\n}\n.dark body::before {\n background:\n radial-gradient(60% 50% at 50% -6%, rgba(221, 0, 172, 0.12), transparent 60%),\n radial-gradient(55% 45% at 12% -8%, rgba(112, 100, 233, 0.18), transparent 60%),\n radial-gradient(50% 40% at 88% -2%, rgba(112, 100, 233, 0.14), transparent 60%),\n radial-gradient(45% 45% at 50% 118%, rgba(112, 100, 233, 0.10), transparent 60%);\n}\n\n/* signature lcai gradient (primary buttons / accents) */\n.bg-gradient-primary {\n background-image: var(--color-gradient-primary);\n}\n.text-gradient {\n background: linear-gradient(94deg, #dd00ac 10%, #7130c3 53%, #7064e9 96%);\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n}\n\n/* minimal scrollbar */\n::-webkit-scrollbar {\n width: 6px;\n height: 6px;\n}\n::-webkit-scrollbar-track {\n background: transparent;\n}\n::-webkit-scrollbar-thumb {\n background: var(--border);\n border-radius: 3px;\n}\n* {\n scrollbar-width: thin;\n scrollbar-color: var(--border) transparent;\n}\n";
|
|
122
|
+
export declare const SCAFFOLD_GLOBALS_CSS = "@import \"tailwindcss\";\n\n/* let Tailwind v4 see streamdown's classes so markdown answers are styled\n (harmless when streamdown isn't installed - the path just matches nothing) */\n@source \"../node_modules/streamdown/dist/index.js\";\n\n/* dark mode via .dark class (we default the app to dark) */\n@custom-variant dark (&:is(.dark, .dark *));\n\n/* design tokens (light) - ported from lcai-chat-v2 */\n:root {\n font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;\n\n --background: #ffffff;\n --primary: #6767e9;\n --primary-600: #5a4fd8;\n --foreground: #09090b;\n --card: #ffffff;\n --card-foreground: #09090b;\n --popover: #ffffff;\n --popover-foreground: hsl(240 10% 3.9%);\n --primary-foreground: #fafafa;\n --secondary: hsl(240 4.8% 95.9%);\n --secondary-foreground: hsl(240 5.9% 10%);\n --muted: hsl(240 4.8% 95.9%);\n --muted-foreground: hsl(240 3.8% 46.1%);\n --accent: hsl(240 4.8% 95.9%);\n --accent-foreground: hsl(240 5.9% 10%);\n --destructive: #ef4d6a;\n --destructive-foreground: hsl(0 0% 98%);\n --success: #15bd77;\n --warning: #eaa53d;\n --border: hsl(240 5.9% 90%);\n --input: hsl(240 5.9% 90%);\n --ring: hsl(240 10% 3.9%);\n --radius: 0.625rem;\n\n --surface-base-subtle: rgba(34, 35, 42, 0.02);\n --surface-base-faint: rgba(14, 18, 27, 0.04);\n --surface-base-light: rgba(204, 206, 239, 0.16);\n --surface-elevation-light: #ffffff;\n\n --content-primary: #0f0f14;\n --content-default: #373842;\n --content-soft: #656678;\n --content-extraLight: #9798b6;\n\n --border-soft: rgba(14, 18, 27, 0.08);\n --border-light: rgba(14, 18, 27, 0.06);\n}\n\n/* design tokens (dark) */\n.dark {\n --background: #070710;\n --foreground: hsl(0 0% 98%);\n --card: #0f0f14;\n --card-foreground: hsl(0 0% 98%);\n --popover: #0f0f14;\n --popover-foreground: hsl(0 0% 98%);\n --primary: #7064e9;\n --primary-600: #8c71f6;\n --primary-foreground: hsl(0 0% 98%);\n --secondary: hsl(240 3.7% 15.9%);\n --secondary-foreground: hsl(0 0% 98%);\n --muted: hsl(240 3.7% 15.9%);\n --muted-foreground: hsl(240 5% 64.9%);\n --accent: hsl(240 3.7% 15.9%);\n --accent-foreground: hsl(0 0% 98%);\n --destructive: #fb5a76;\n --destructive-foreground: hsl(0 0% 98%);\n --success: #22d68a;\n --warning: #f5be5c;\n --border: hsl(240 3.7% 15.9%);\n --input: hsl(240 3.7% 15.9%);\n --ring: hsl(240 4.9% 83.9%);\n\n --surface-base-subtle: rgba(204, 206, 239, 0.02);\n --surface-base-faint: rgba(204, 206, 239, 0.04);\n --surface-base-light: rgba(204, 206, 239, 0.08);\n --surface-elevation-light: #0f0f14;\n\n --content-primary: #cccef0;\n --content-default: #9798b6;\n --content-soft: rgba(154, 156, 207, 0.8);\n --content-extraLight: #9798b6;\n\n --border-soft: rgba(204, 206, 239, 0.12);\n --border-light: rgba(204, 206, 239, 0.08);\n}\n\n/* theme mapping (Tailwind v4 @theme) */\n@theme inline {\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-lg: var(--radius);\n\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-600: var(--primary-600);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-destructive-foreground: var(--destructive-foreground);\n --color-success: var(--success);\n --color-warning: var(--warning);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n\n --color-surface-base-subtle: var(--surface-base-subtle);\n --color-surface-base-faint: var(--surface-base-faint);\n --color-surface-base-light: var(--surface-base-light);\n --color-surface-elevation-light: var(--surface-elevation-light);\n --color-surface-base-brand-default: #693ee0;\n --color-surface-base-brand-strong: #8c71f6;\n\n --color-content-primary: var(--content-primary);\n --color-content-default: var(--content-default);\n --color-content-soft: var(--content-soft);\n --color-content-extraLight: var(--content-extraLight);\n\n --color-bdr-soft: var(--border-soft);\n --color-bdr-light: var(--border-light);\n\n --color-gradient-primary: linear-gradient(270deg, #7064e9 0%, #dd00ac 100%);\n}\n\n@layer base {\n * {\n border-color: var(--border);\n }\n body {\n background-color: var(--background);\n color: var(--foreground);\n overflow-x: hidden;\n }\n html {\n overflow-x: hidden;\n }\n button {\n cursor: pointer;\n }\n button:disabled {\n cursor: not-allowed;\n }\n /* visible keyboard focus across interactive elements */\n a:focus-visible,\n button:focus-visible,\n input:focus-visible,\n select:focus-visible,\n textarea:focus-visible {\n outline: 2px solid var(--primary);\n outline-offset: 2px;\n border-radius: 6px;\n }\n}\n\n/* respect reduced-motion: kill non-essential animation */\n@media (prefers-reduced-motion: reduce) {\n *,\n ::before,\n ::after {\n animation-duration: 0.001ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.001ms !important;\n scroll-behavior: auto !important;\n }\n}\n\n/* ambient app background (gradient mesh behind everything) */\nbody::before {\n content: \"\";\n position: fixed;\n inset: 0;\n z-index: -1;\n pointer-events: none;\n background:\n radial-gradient(60% 50% at 50% -6%, rgba(221, 0, 172, 0.10), transparent 60%),\n radial-gradient(55% 45% at 12% -8%, rgba(112, 100, 233, 0.14), transparent 60%),\n radial-gradient(50% 40% at 88% -2%, rgba(112, 100, 233, 0.12), transparent 60%),\n radial-gradient(45% 45% at 50% 115%, rgba(112, 100, 233, 0.07), transparent 60%);\n}\n.dark body::before {\n background:\n radial-gradient(60% 50% at 50% -6%, rgba(221, 0, 172, 0.12), transparent 60%),\n radial-gradient(55% 45% at 12% -8%, rgba(112, 100, 233, 0.18), transparent 60%),\n radial-gradient(50% 40% at 88% -2%, rgba(112, 100, 233, 0.14), transparent 60%),\n radial-gradient(45% 45% at 50% 118%, rgba(112, 100, 233, 0.10), transparent 60%);\n}\n\n/* signature lcai gradient (primary buttons / accents) */\n.bg-gradient-primary {\n background-image: var(--color-gradient-primary);\n}\n/* the lcai-chat connect-button gradient (pink -> purple) */\n.bg-gradient-btn {\n background-image: linear-gradient(94deg, #dd00ac 10.66%, #7130c3 53.03%, #410093 96.34%);\n background-size: 200% auto;\n}\n@keyframes pulse-dot {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.4; }\n}\n.animate-pulse-dot {\n animation: pulse-dot 1.6s ease-in-out infinite;\n}\n.text-gradient {\n background: linear-gradient(94deg, #dd00ac 10%, #7130c3 53%, #7064e9 96%);\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n}\n\n/* minimal scrollbar */\n::-webkit-scrollbar {\n width: 6px;\n height: 6px;\n}\n::-webkit-scrollbar-track {\n background: transparent;\n}\n::-webkit-scrollbar-thumb {\n background: var(--border);\n border-radius: 3px;\n}\n* {\n scrollbar-width: thin;\n scrollbar-color: var(--border) transparent;\n}\n";
|
|
123
123
|
export interface ScaffoldWiring {
|
|
124
124
|
written: WrittenFile[];
|
|
125
125
|
/** The route now also served at `/` (e.g. "/chat-web3"), or null if nothing was wired. */
|
package/dist/add.js
CHANGED
|
@@ -961,14 +961,16 @@ const NEXTJS_CHAT_WEB3_PAGE = `// app/chat-web3/page.tsx
|
|
|
961
961
|
// turn plus a small gas amount.
|
|
962
962
|
"use client";
|
|
963
963
|
|
|
964
|
-
import { useEffect, useState } from "react";
|
|
964
|
+
import { useEffect, useRef, useState } from "react";
|
|
965
965
|
import { useAccount, useWalletClient, usePublicClient } from "wagmi";
|
|
966
966
|
import { siweSignIn, GatewayClient, runInference, estimateJobFee, NETWORKS } from "lightnode-sdk";
|
|
967
|
+
import { Streamdown } from "streamdown";
|
|
967
968
|
import { ConnectButton } from "@/components/connect-button";
|
|
968
969
|
|
|
969
970
|
type Turn = {
|
|
970
971
|
role: "user" | "assistant";
|
|
971
972
|
text: string;
|
|
973
|
+
streaming?: boolean;
|
|
972
974
|
worker?: string | null;
|
|
973
975
|
jobId?: string | null;
|
|
974
976
|
submitTx?: \`0x\${string}\` | null;
|
|
@@ -977,6 +979,30 @@ type Turn = {
|
|
|
977
979
|
|
|
978
980
|
const MODEL = "llama3-8b";
|
|
979
981
|
|
|
982
|
+
/** The LightChain atom mark (gradient logo). No wordmark - the viewBox frames
|
|
983
|
+
* the atom only. Used as the assistant avatar and the input glyph. */
|
|
984
|
+
function LcaiMark({ className }: { className?: string }) {
|
|
985
|
+
return (
|
|
986
|
+
<svg
|
|
987
|
+
viewBox="854.3951253356933 398.23541259765625 186.60832495117188 198.4013696411746"
|
|
988
|
+
className={className}
|
|
989
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
990
|
+
aria-hidden="true"
|
|
991
|
+
>
|
|
992
|
+
<g transform="translate(856.3148789999999, 398.23539999999997) scale(0.6266964564006055)">
|
|
993
|
+
<linearGradient gradientTransform="matrix(1 0 0 1 0 -244)" gradientUnits="userSpaceOnUse" id="lcai-mark-grad" x1="-0.0000002" x2="298.8796082" y1="401.5" y2="401.5">
|
|
994
|
+
<stop offset="0" stopColor="rgb(48, 5, 250)" />
|
|
995
|
+
<stop offset="1" stopColor="rgb(255, 18, 251)" />
|
|
996
|
+
</linearGradient>
|
|
997
|
+
<path
|
|
998
|
+
fill="url(#lcai-mark-grad)"
|
|
999
|
+
d="M280.0912476,168.2428284c0.0187378-0.036911,0.0380554-0.0726929,0.0562134-0.1096191c16.2681885-32.6010895,17.265564-64.3445282,2.8092651-89.3834915c-12.8778992-22.3064003-36.5042877-36.642292-67.219101-41.070858C196.544342,13.2930756,172.316452,0,146.5589905,0c-22.3245773,0-43.5001221,9.986846-61.2456131,28.5235424C59.731987,30.5614643,38.6132431,40.6585007,24.5028381,57.9581261C6.2308226,80.3639221,2.1413448,111.8585815,12.9886856,146.6407318c0.0119276,0.0391846,0.0255585,0.0778198,0.0380545,0.1170044c-0.0181751,0.0363464-0.0380545,0.0727081-0.0562305,0.1090546c-16.2681713,32.6010895-17.2655487,64.3445282-2.8092442,89.3834991c12.8778811,22.3069611,36.5042725,36.6422882,67.2190933,41.0714264C96.5736389,301.7069092,120.8015289,315,146.5589905,315c22.3296814,0,43.5103455-9.991394,61.2581024-28.5365906c25.5706024-2.0402222,46.6916199-12.125885,60.7980499-29.4215393c18.2720032-22.4057922,22.3614807-53.9004517,11.5141602-88.6826019C280.1173706,168.3206482,280.1037292,168.2814484,280.0912476,168.2428284z M271.8764954,85.1474762c10.6303711,18.4145813,11.1694031,41.5411453,1.7635803,66.0655212c-3.7219849-8.3783264-8.2141418-16.6447449-13.4100647-24.7055588l-4.6642761,17.0429001c4.3473511,7.8126068,7.9301758,15.6831512,10.7121582,23.4855347c-4.3819885,8.0193481-9.6506042,15.8308258-15.7041626,23.3338776c1.5176544-10.6928558,2.3207703-21.6884308,2.3207703-32.8691864c0-29.667511-5.4985657-60.093277-17.7237091-87.3391113c-2.6733246-5.9579468-5.6783905-11.7689896-9.0385132-17.369133C246.8721771,58.2199669,262.7427673,69.3285828,271.8764954,85.1474762z M53.0189972,157.5005646c0-17.7983093,2.0930176-34.8525772,5.9098625-50.615242c11.8929939-11.332962,25.6574974-21.6162949,40.8601341-30.3939056c17.8886261-10.3276367,36.5854874-17.8778381,55.0960617-22.4290848c17.2502136,7.3440208,34.5396118,17.6932373,50.7930145,30.9488297c11.4465637,9.3348007,21.5856323,19.4636459,30.3081512,30.0235825c2.6712189,13.4345093,4.1127625,27.6942902,4.1127625,42.4658203c0,17.79776-2.0930176,34.852005-5.9092865,50.6141052c-11.8930054,11.3329773-25.6575012,21.6163025-40.8607025,30.3939209c-17.8818207,10.3236542-36.5724335,17.8908844-55.0767517,22.4427032c-17.2558975-7.3440094-34.5521164-17.7017517-50.811203-30.9624481h-0.0011368c-11.4465637-9.3348083-21.5856247-19.4636536-30.3081436-30.0235901C54.460537,186.531311,53.0189972,172.27211,53.0189972,157.5005646z M197.5405884,36.2367516c-8.420929-0.1454048-17.0355225,0.3947487-25.7472534,1.5812645l10.6093597,11.7066994c4.158783-0.3368149,8.2834625-0.5191383,12.357605-0.5191383c2.894455,0,5.7661743,0.0851974,8.6072235,0.2578659c1.8720703,0.1141663,3.7151794,0.2686577,5.5338593,0.456089c7.9432373,11.0063782,14.6692963,24.0733986,19.8174896,38.6586342c-4.7466278-4.5887375-9.7346497-9.0269547-14.9538574-13.283989c-5.9595642-4.8602829-12.1525574-9.4351349-18.5579681-13.6909294c-6.3523102-4.2205162-12.9407349-7.9979477-19.6017914-11.7028999c-4.8133698-2.6772537-9.9029083-5.0026283-14.9892578-7.1101379c-1.8141327-0.7520103-3.3374634-1.3887177-4.6540527-1.9288712c-15.6155548-6.2455406-31.4423981-10.2702694-46.9034653-11.8191586c-1.6102371-0.1607399-3.2039948-0.2845592-4.789238-0.3907719c12.707489-10.0067272,27.0797272-15.6558857,42.2897491-15.6558857C165.352417,12.7955227,182.865036,21.4209137,197.5405884,36.2367516z M34.4186859,66.0450745c9.6119766-11.7850838,23.0726089-19.3455086,38.8551559-22.8698425c-0.9178619,1.2932968-1.8266373,2.6036339-2.717804,3.9503212c-7.5609894,11.4329338-13.7923317,24.314785-18.6122322,38.2065163l15.7944679-5.6764221c6.2233963-15.0276947,14.1956024-28.1611671,23.4639511-38.7228127c1.3574829-0.0494118,2.7212067-0.0846291,4.0997009-0.0846291c12.3808975,0,25.5910492,1.9907799,39.0925751,5.8922577c-13.8752594,4.7176666-27.6653214,10.9700241-41.0032654,18.6707382c-9.0180283,5.2061462-17.6032944,11.0505371-25.9167862,17.3136139c-6.0140381,4.5307617-12.0375252,9.2800751-17.314682,14.6695099c-0.9797707,0.965004-1.8680954,1.8391342-2.6734962,2.6308975c-0.0170364,0.0653229-0.0329399,0.1312103-0.0505486,0.1965256c-9.7846451,9.6653671-18.3208618,20.0276489-25.3808918,30.852272C16.8799381,106.224762,20.5229797,83.083992,34.4186859,66.0450745z M21.2414799,229.8525238c-10.630372-18.4140167-11.1693878-41.5405731-1.763588-66.0655212c4.1763802,9.4012604,9.3228741,18.6616516,15.3446293,27.6482849l4.0724411-17.6199799c-4.9550858-8.587326-8.9911728-17.2598572-12.054306-25.851181c4.381422-8.0193481,9.650032-15.8308258,15.7035942-23.3338776c-1.5176506,10.6934204-2.3207779,21.6895752-2.3207779,32.8703156c0,7.742981,0.3608093,15.5649719,1.0776787,23.2746582c2.6225128,28.2041779,11.0045586,56.9674835,25.6845512,81.4324493C46.2463646,256.7800293,30.3752155,245.6719818,21.2414799,229.8525238z M95.5614929,278.7479248c0.9189987,0.0158997,1.8345871,0.0408936,2.7575607,0.0408936c7.9733429,0,16.1102676-0.612854,24.3289871-1.7931213l-10.7837296-11.6033325c-7.5093002,0.662262-14.9044418,0.7838135-22.1138535,0.3441772c-1.8720703-0.1135864-3.7151718-0.2680664-5.5338593-0.4555054c-7.9438095-11.0069427-14.6698608-24.0739594-19.8180618-38.6603394c4.7472,4.5893097,9.7357941,9.0280914,14.9555588,13.2851257h-0.0011292c11.9242325,9.7244415,24.5255051,18.0942383,37.4562073,24.9662781c-0.021019,0.0028381-0.0420303,0.0050964-0.0630493,0.0073547c5.3225708,2.7774658,11.9242401,6.0115356,18.2651978,8.5464478c2.2242279,0.8894653,4.0071259,1.6102295,5.4679718,2.2071838c14.5341187,5.5088806,29.2147827,9.0860291,43.5802155,10.5247192c1.6107941,0.1613159,3.2039948,0.2845764,4.7897949,0.3907776c-12.7080536,10.0067444-27.0802917,15.6558838-42.2903137,15.6558838C127.7593155,302.2044678,110.240448,293.5728455,95.5614929,278.7479248z M258.6993103,248.9549255c-9.6131287,11.7862244-23.0743256,19.3534546-38.8602753,22.8778076c0.9195557-1.2955933,1.8305969-2.6087646,2.7229004-3.9582825c7.3122253-11.0557861,13.3947449-23.4577026,18.1470642-36.8263245l-15.8035583,5.4151459c-6.1529694,14.5613861-13.9542084,27.3091888-22.9919586,37.6073151c-13.5583191,0.4913025-28.2117157-1.4767761-43.229187-5.8201294c13.8883209-4.7193909,27.6931458-10.9535522,41.04245-18.6616669c9.6801453-5.5883789,18.8150177-11.7680359,27.3148804-18.427063c-0.0124969,0.0312347-0.0238647,0.0630493-0.0363464,0.0942841c4.5438538-3.6339569,9.8499603-8.1062622,14.4875336-12.6194458c3.7958374-3.6941681,6.0331268-5.820694,7.3400421-7.0401611c8.474884-8.7463684,15.9393005-18.0238037,22.2302856-27.6698608C276.2380371,208.775238,272.5950012,231.9165802,258.6993103,248.9549255z M151.8601074,99.7067947l2.0352783,43.1479874c0.1197662,2.5387726,2.1956635,4.5453033,4.7370453,4.5787506l30.6875916,0.4037781c3.7883453,0.0498505,6.0318604,4.2594757,3.9608765,7.4320374l-40.7515411,62.4279022c-2.6121979,4.0016479-8.8297119,2.1519318-8.8297119-2.6268463v-42.6512451c0-2.6540527-2.151535-4.8055878-4.805603-4.8055878h-32.7028122c-3.7936096,0-6.0953522-4.18367-4.056221-7.3826447c9.1347427-14.3305359,29.4064636-45.9985199,40.9515228-63.0014496C145.6810608,93.4083862,151.6424866,95.0932236,151.8601074,99.7067947z"
|
|
1000
|
+
/>
|
|
1001
|
+
</g>
|
|
1002
|
+
</svg>
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
980
1006
|
export default function ChatWeb3() {
|
|
981
1007
|
const { address, chain } = useAccount();
|
|
982
1008
|
const network: "mainnet" | "testnet" | null =
|
|
@@ -990,6 +1016,7 @@ export default function ChatWeb3() {
|
|
|
990
1016
|
const [busyStage, setBusyStage] = useState("");
|
|
991
1017
|
const [err, setErr] = useState<string | null>(null);
|
|
992
1018
|
const [feeLcai, setFeeLcai] = useState<number | null>(null);
|
|
1019
|
+
const endRef = useRef<HTMLDivElement>(null);
|
|
993
1020
|
|
|
994
1021
|
// Read the on-chain fee for the connected network so we can show the
|
|
995
1022
|
// visitor the real cost per turn before they click Send.
|
|
@@ -1003,6 +1030,11 @@ export default function ChatWeb3() {
|
|
|
1003
1030
|
return () => { cancelled = true; };
|
|
1004
1031
|
}, [network]);
|
|
1005
1032
|
|
|
1033
|
+
// Keep the latest turn (and the "writing on chain" indicator) in view.
|
|
1034
|
+
useEffect(() => {
|
|
1035
|
+
endRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1036
|
+
}, [turns, busy]);
|
|
1037
|
+
|
|
1006
1038
|
/** Build a single prompt from history + new user input. */
|
|
1007
1039
|
function composePrompt(history: Turn[], next: string, system: string): string {
|
|
1008
1040
|
const lines: string[] = [];
|
|
@@ -1014,6 +1046,16 @@ export default function ChatWeb3() {
|
|
|
1014
1046
|
return system ? \`\${system}\\n\\n\${lines.join("\\n\\n")}\` : lines.join("\\n\\n");
|
|
1015
1047
|
}
|
|
1016
1048
|
|
|
1049
|
+
/** Patch the trailing assistant turn (the streaming placeholder) in place. */
|
|
1050
|
+
function patchLastAssistant(patch: Partial<Turn>) {
|
|
1051
|
+
setTurns((prev) => {
|
|
1052
|
+
if (prev.length === 0) return prev;
|
|
1053
|
+
const last = prev[prev.length - 1];
|
|
1054
|
+
if (last.role !== "assistant") return prev;
|
|
1055
|
+
return [...prev.slice(0, -1), { ...last, ...patch }];
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1017
1059
|
async function send() {
|
|
1018
1060
|
if (!walletClient || !publicClient || !address || !network) {
|
|
1019
1061
|
setErr("Connect a wallet on LightChain mainnet (9200) or testnet (8200) first.");
|
|
@@ -1024,8 +1066,8 @@ export default function ChatWeb3() {
|
|
|
1024
1066
|
setBusy(true);
|
|
1025
1067
|
setErr(null);
|
|
1026
1068
|
const history = [...turns];
|
|
1027
|
-
// Optimistic user bubble
|
|
1028
|
-
setTurns([...history, { role: "user", text: next }]);
|
|
1069
|
+
// Optimistic user bubble + an empty assistant turn we stream tokens into.
|
|
1070
|
+
setTurns([...history, { role: "user", text: next }, { role: "assistant", text: "", streaming: true }]);
|
|
1029
1071
|
setInput("");
|
|
1030
1072
|
try {
|
|
1031
1073
|
const system = "You are a concise assistant. Reply in one or two short sentences.";
|
|
@@ -1045,16 +1087,21 @@ export default function ChatWeb3() {
|
|
|
1045
1087
|
model: MODEL,
|
|
1046
1088
|
jobCompletedTimeoutMs: 120_000,
|
|
1047
1089
|
maxRetries: 1,
|
|
1090
|
+
// Stream each decrypted chunk into the assistant bubble as it arrives.
|
|
1091
|
+
onChunk: (_chunk, totalSoFar) => {
|
|
1092
|
+
setBusyStage("");
|
|
1093
|
+
patchLastAssistant({ text: totalSoFar });
|
|
1094
|
+
},
|
|
1048
1095
|
});
|
|
1049
1096
|
|
|
1050
|
-
|
|
1051
|
-
role: "assistant",
|
|
1097
|
+
patchLastAssistant({
|
|
1052
1098
|
text: result.answer,
|
|
1099
|
+
streaming: false,
|
|
1053
1100
|
worker: result.worker,
|
|
1054
1101
|
jobId: result.jobId?.toString() ?? null,
|
|
1055
1102
|
submitTx: result.txs?.submitJob ?? null,
|
|
1056
1103
|
jobCompletedTx: result.txs?.jobCompleted ?? null,
|
|
1057
|
-
}
|
|
1104
|
+
});
|
|
1058
1105
|
} catch (e) {
|
|
1059
1106
|
// Roll back the optimistic user bubble so the visitor can retry.
|
|
1060
1107
|
setTurns(history);
|
|
@@ -1074,10 +1121,10 @@ export default function ChatWeb3() {
|
|
|
1074
1121
|
}
|
|
1075
1122
|
|
|
1076
1123
|
return (
|
|
1077
|
-
<main className="mx-auto flex min-h-screen w-full max-w-
|
|
1078
|
-
<header className="flex items-center justify-between gap-3
|
|
1124
|
+
<main className="mx-auto flex min-h-screen w-full max-w-3xl flex-col px-4 py-6">
|
|
1125
|
+
<header className="flex items-center justify-between gap-3 pb-6">
|
|
1079
1126
|
<div className="min-w-0">
|
|
1080
|
-
<h1 className="
|
|
1127
|
+
<h1 className="font-semibold text-foreground">Chat</h1>
|
|
1081
1128
|
<p className="truncate text-xs text-muted-foreground">
|
|
1082
1129
|
{network ? (
|
|
1083
1130
|
<>Signed from your wallet on {network} · {feeLcai != null ? feeLcai + " LCAI" : "..."}/turn + gas</>
|
|
@@ -1089,10 +1136,13 @@ export default function ChatWeb3() {
|
|
|
1089
1136
|
<ConnectButton />
|
|
1090
1137
|
</header>
|
|
1091
1138
|
|
|
1092
|
-
<div className="flex flex-1 flex-col gap-
|
|
1139
|
+
<div className="flex flex-1 flex-col gap-6 overflow-y-auto pb-6">
|
|
1093
1140
|
{turns.length === 0 ? (
|
|
1094
|
-
<div className="flex flex-1 flex-col items-center justify-center gap-
|
|
1095
|
-
<
|
|
1141
|
+
<div className="flex flex-1 flex-col items-center justify-center gap-4 text-center">
|
|
1142
|
+
<LcaiMark className="size-12" />
|
|
1143
|
+
<h2 className="text-3xl font-medium tracking-tight text-foreground">
|
|
1144
|
+
Start talking with <span className="text-gradient">AI Chat</span>
|
|
1145
|
+
</h2>
|
|
1096
1146
|
<p className="max-w-sm text-sm text-muted-foreground">
|
|
1097
1147
|
Connect your wallet and send a message. Each turn is signed and paid from your
|
|
1098
1148
|
own wallet, no backend required.
|
|
@@ -1104,44 +1154,63 @@ export default function ChatWeb3() {
|
|
|
1104
1154
|
)}
|
|
1105
1155
|
</div>
|
|
1106
1156
|
) : (
|
|
1107
|
-
turns.map((t, i) =>
|
|
1108
|
-
|
|
1109
|
-
key={i}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1157
|
+
turns.map((t, i) =>
|
|
1158
|
+
t.role === "user" ? (
|
|
1159
|
+
<div key={i} className="flex justify-end">
|
|
1160
|
+
<div className="w-fit max-w-[85%] whitespace-pre-wrap break-words rounded-2xl bg-surface-base-faint px-4 py-2.5 text-sm text-foreground">
|
|
1161
|
+
{t.text}
|
|
1162
|
+
</div>
|
|
1163
|
+
</div>
|
|
1164
|
+
) : (
|
|
1165
|
+
<div key={i} className="group flex gap-3">
|
|
1166
|
+
<LcaiMark className="mt-0.5 size-7 shrink-0" />
|
|
1167
|
+
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
|
1168
|
+
{t.text ? (
|
|
1169
|
+
<div className="max-w-none text-sm leading-relaxed text-foreground [&_*:first-child]:mt-0 [&_*:last-child]:mb-0">
|
|
1170
|
+
<Streamdown>{t.text}</Streamdown>
|
|
1171
|
+
</div>
|
|
1172
|
+
) : (
|
|
1173
|
+
<div className="animate-pulse-dot pt-1 text-sm text-muted-foreground">
|
|
1174
|
+
{busyStage || "Writing on chain..."}
|
|
1175
|
+
</div>
|
|
1124
1176
|
)}
|
|
1125
|
-
{t.jobId && <span>job #{t.jobId}</span>}
|
|
1126
1177
|
{t.submitTx && (
|
|
1127
|
-
<
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1178
|
+
<div className="flex flex-wrap items-center gap-3 text-[11px] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100">
|
|
1179
|
+
<button
|
|
1180
|
+
type="button"
|
|
1181
|
+
onClick={() => navigator.clipboard?.writeText(t.text)}
|
|
1182
|
+
className="inline-flex items-center gap-1 hover:text-foreground"
|
|
1183
|
+
aria-label="Copy"
|
|
1184
|
+
>
|
|
1185
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
1186
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
|
|
1187
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
1188
|
+
</svg>
|
|
1189
|
+
Copy
|
|
1190
|
+
</button>
|
|
1191
|
+
{t.worker && (
|
|
1192
|
+
<a className="hover:text-foreground hover:underline" href={\`https://\${network}.lightscan.app/address/\${t.worker}\`} target="_blank" rel="noopener noreferrer">worker</a>
|
|
1193
|
+
)}
|
|
1194
|
+
{t.jobId && <span>job #{t.jobId}</span>}
|
|
1195
|
+
{t.submitTx && (
|
|
1196
|
+
<a className="hover:text-foreground hover:underline" href={\`https://\${network}.lightscan.app/tx/\${t.submitTx}\`} target="_blank" rel="noopener noreferrer">submitJob</a>
|
|
1197
|
+
)}
|
|
1198
|
+
{t.jobCompletedTx && (
|
|
1199
|
+
<a className="hover:text-foreground hover:underline" href={\`https://\${network}.lightscan.app/tx/\${t.jobCompletedTx}\`} target="_blank" rel="noopener noreferrer">completed</a>
|
|
1200
|
+
)}
|
|
1201
|
+
</div>
|
|
1135
1202
|
)}
|
|
1136
1203
|
</div>
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
)
|
|
1204
|
+
</div>
|
|
1205
|
+
)
|
|
1206
|
+
)
|
|
1140
1207
|
)}
|
|
1208
|
+
<div ref={endRef} />
|
|
1141
1209
|
</div>
|
|
1142
1210
|
|
|
1143
|
-
<div className="
|
|
1144
|
-
<div className="flex items-
|
|
1211
|
+
<div className="rounded-2xl border border-border bg-card p-3">
|
|
1212
|
+
<div className="flex items-start gap-2">
|
|
1213
|
+
<LcaiMark className="mt-2 size-5 shrink-0" />
|
|
1145
1214
|
<textarea
|
|
1146
1215
|
value={input}
|
|
1147
1216
|
onChange={(e) => setInput(e.target.value)}
|
|
@@ -1149,16 +1218,31 @@ export default function ChatWeb3() {
|
|
|
1149
1218
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); if (!busy && input.trim()) send(); }
|
|
1150
1219
|
}}
|
|
1151
1220
|
rows={1}
|
|
1152
|
-
placeholder=
|
|
1153
|
-
className="max-h-40 min-h-[
|
|
1221
|
+
placeholder="Send a message..."
|
|
1222
|
+
className="max-h-40 min-h-[44px] w-full resize-none bg-transparent px-2 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
|
1154
1223
|
/>
|
|
1224
|
+
</div>
|
|
1225
|
+
<div className="mt-1 flex items-center justify-between gap-2">
|
|
1226
|
+
<span className="inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs font-medium text-muted-foreground">
|
|
1227
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
1228
|
+
<rect x="4" y="4" width="16" height="16" rx="2" />
|
|
1229
|
+
<rect x="9" y="9" width="6" height="6" />
|
|
1230
|
+
<path d="M9 2v2M15 2v2M9 20v2M15 20v2M2 9h2M2 15h2M20 9h2M20 15h2" />
|
|
1231
|
+
</svg>
|
|
1232
|
+
{MODEL}
|
|
1233
|
+
</span>
|
|
1155
1234
|
<button
|
|
1156
1235
|
type="button"
|
|
1157
1236
|
onClick={() => send()}
|
|
1158
1237
|
disabled={busy || !input.trim() || !address || !network}
|
|
1159
|
-
className="shrink-0 rounded-
|
|
1238
|
+
className="flex size-9 shrink-0 items-center justify-center rounded-full bg-gradient-primary text-white transition hover:brightness-110 disabled:cursor-not-allowed disabled:bg-none disabled:bg-muted disabled:text-muted-foreground"
|
|
1239
|
+
aria-label={busy ? "Working" : "Send"}
|
|
1160
1240
|
>
|
|
1161
|
-
{busy ? (
|
|
1241
|
+
{busy ? (
|
|
1242
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2" /></svg>
|
|
1243
|
+
) : (
|
|
1244
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 19V5M5 12l7-7 7 7" /></svg>
|
|
1245
|
+
)}
|
|
1162
1246
|
</button>
|
|
1163
1247
|
</div>
|
|
1164
1248
|
{err && (
|
|
@@ -1825,7 +1909,8 @@ export function addChatWeb3(opts = {}) {
|
|
|
1825
1909
|
written.push(writeFile(path.join(cwd, "app/chat-web3/page.tsx"), NEXTJS_CHAT_WEB3_PAGE, force));
|
|
1826
1910
|
return {
|
|
1827
1911
|
written,
|
|
1828
|
-
|
|
1912
|
+
// streamdown renders the assistant answers as markdown (bold, lists, code).
|
|
1913
|
+
install: `npm install lightnode-sdk viem streamdown` + (hasWagmi ? "" : " wagmi @tanstack/react-query"),
|
|
1829
1914
|
template,
|
|
1830
1915
|
network,
|
|
1831
1916
|
needsWagmi: !hasWagmi,
|
|
@@ -1982,9 +2067,13 @@ export function ConnectButton() {
|
|
|
1982
2067
|
type="button"
|
|
1983
2068
|
onClick={() => connect({ connector })}
|
|
1984
2069
|
disabled={isPending}
|
|
1985
|
-
|
|
2070
|
+
className="bg-gradient-btn inline-flex items-center gap-2 rounded-[10px] px-5 py-2.5 text-sm font-medium tracking-wide text-white transition hover:brightness-110 disabled:opacity-60"
|
|
1986
2071
|
>
|
|
1987
|
-
|
|
2072
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
2073
|
+
<path d="M19 7V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2" />
|
|
2074
|
+
<path d="M21 12h-6a2 2 0 0 0 0 4h6v-4Z" />
|
|
2075
|
+
</svg>
|
|
2076
|
+
{isPending ? "Connecting..." : "Connect Wallet"}
|
|
1988
2077
|
</button>
|
|
1989
2078
|
);
|
|
1990
2079
|
}
|
|
@@ -1995,7 +2084,7 @@ export function ConnectButton() {
|
|
|
1995
2084
|
type="button"
|
|
1996
2085
|
onClick={() => switchChain({ chainId: 9200 })}
|
|
1997
2086
|
disabled={switching}
|
|
1998
|
-
|
|
2087
|
+
className="rounded-[10px] border border-destructive/40 bg-destructive/10 px-4 py-2 text-sm font-medium text-destructive transition hover:bg-destructive/20 disabled:opacity-60"
|
|
1999
2088
|
>
|
|
2000
2089
|
{switching ? "Switching..." : "Switch to LightChain"}
|
|
2001
2090
|
</button>
|
|
@@ -2006,9 +2095,12 @@ export function ConnectButton() {
|
|
|
2006
2095
|
<button
|
|
2007
2096
|
type="button"
|
|
2008
2097
|
onClick={() => disconnect()}
|
|
2009
|
-
|
|
2098
|
+
className="group inline-flex items-center gap-2 rounded-[10px] border border-border bg-card px-4 py-2 font-mono text-sm text-foreground transition hover:border-primary"
|
|
2099
|
+
title={\`\${chain?.name} - click to disconnect\`}
|
|
2010
2100
|
>
|
|
2011
|
-
|
|
2101
|
+
<span className="size-2 rounded-full bg-success" />
|
|
2102
|
+
{address ? shortAddress(address) : "(unknown)"}
|
|
2103
|
+
<span className="text-muted-foreground group-hover:text-foreground">disconnect</span>
|
|
2012
2104
|
</button>
|
|
2013
2105
|
);
|
|
2014
2106
|
}
|
|
@@ -2106,6 +2198,10 @@ export function patchLayoutWithProviders(cwd = process.cwd()) {
|
|
|
2106
2198
|
// installs default to the real look instead of the create-next-app starter.
|
|
2107
2199
|
export const SCAFFOLD_GLOBALS_CSS = `@import "tailwindcss";
|
|
2108
2200
|
|
|
2201
|
+
/* let Tailwind v4 see streamdown's classes so markdown answers are styled
|
|
2202
|
+
(harmless when streamdown isn't installed - the path just matches nothing) */
|
|
2203
|
+
@source "../node_modules/streamdown/dist/index.js";
|
|
2204
|
+
|
|
2109
2205
|
/* dark mode via .dark class (we default the app to dark) */
|
|
2110
2206
|
@custom-variant dark (&:is(.dark, .dark *));
|
|
2111
2207
|
|
|
@@ -2304,6 +2400,18 @@ body::before {
|
|
|
2304
2400
|
.bg-gradient-primary {
|
|
2305
2401
|
background-image: var(--color-gradient-primary);
|
|
2306
2402
|
}
|
|
2403
|
+
/* the lcai-chat connect-button gradient (pink -> purple) */
|
|
2404
|
+
.bg-gradient-btn {
|
|
2405
|
+
background-image: linear-gradient(94deg, #dd00ac 10.66%, #7130c3 53.03%, #410093 96.34%);
|
|
2406
|
+
background-size: 200% auto;
|
|
2407
|
+
}
|
|
2408
|
+
@keyframes pulse-dot {
|
|
2409
|
+
0%, 100% { opacity: 1; }
|
|
2410
|
+
50% { opacity: 0.4; }
|
|
2411
|
+
}
|
|
2412
|
+
.animate-pulse-dot {
|
|
2413
|
+
animation: pulse-dot 1.6s ease-in-out infinite;
|
|
2414
|
+
}
|
|
2307
2415
|
.text-gradient {
|
|
2308
2416
|
background: linear-gradient(94deg, #dd00ac 10%, #7130c3 53%, #7064e9 96%);
|
|
2309
2417
|
-webkit-background-clip: text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightnode-sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Read-only TypeScript client for LightChain AI: workers, jobs, models, on-chain registration, and per-model network analytics. Independent, community-built (not an official LightChain package).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|