rift-ds 1.7.0 → 1.9.0

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.
Files changed (131) hide show
  1. package/README.md +31 -8
  2. package/bin/rift-ds.mjs +142 -29
  3. package/bin/templates/chat/.env.chat.example +21 -0
  4. package/bin/templates/chat/app/api/chat/feedback/route.ts +12 -0
  5. package/bin/templates/chat/app/api/chat/followups/route.ts +23 -0
  6. package/bin/templates/chat/app/api/chat/guardrails.ts +18 -0
  7. package/bin/templates/chat/app/api/chat/route.ts +31 -0
  8. package/bin/templates/chat/components/chat/ChatMount.tsx +52 -0
  9. package/bin/templates/chat/components/chat/models.ts +29 -0
  10. package/chat/AssistantTurn.d.ts +5 -0
  11. package/chat/AssistantTurn.js +82 -0
  12. package/chat/ChatAgentPane.css +56 -0
  13. package/chat/ChatAgentPane.d.ts +24 -0
  14. package/chat/ChatAgentPane.js +28 -0
  15. package/chat/ChatArtifactCard.d.ts +13 -0
  16. package/chat/ChatArtifactCard.js +21 -0
  17. package/chat/ChatArtifactPane.d.ts +18 -0
  18. package/chat/ChatArtifactPane.js +43 -0
  19. package/chat/ChatLauncher.d.ts +64 -0
  20. package/chat/ChatLauncher.js +347 -0
  21. package/chat/ChatProvider.d.ts +55 -0
  22. package/chat/ChatProvider.js +196 -0
  23. package/chat/ChatTabs.d.ts +13 -0
  24. package/chat/ChatTabs.js +24 -0
  25. package/chat/ChatThreads.d.ts +26 -0
  26. package/chat/ChatThreads.js +55 -0
  27. package/chat/ChatWidget.css +1259 -0
  28. package/chat/ChatWidget.d.ts +115 -0
  29. package/chat/ChatWidget.js +709 -0
  30. package/chat/DemoWelcome.d.ts +13 -0
  31. package/chat/DemoWelcome.js +131 -0
  32. package/chat/FollowupSuggestions.d.ts +23 -0
  33. package/chat/FollowupSuggestions.js +34 -0
  34. package/chat/ResponseActions.d.ts +18 -0
  35. package/chat/ResponseActions.js +79 -0
  36. package/chat/TurnContent.d.ts +11 -0
  37. package/chat/TurnContent.js +19 -0
  38. package/chat/artifacts.d.ts +5 -0
  39. package/chat/artifacts.js +14 -0
  40. package/chat/context.d.ts +82 -0
  41. package/chat/context.js +29 -0
  42. package/chat/demo-agent-panes.d.ts +5 -0
  43. package/chat/demo-agent-panes.js +49 -0
  44. package/chat/demo-agent.d.ts +3 -0
  45. package/chat/demo-agent.js +28 -0
  46. package/chat/demo-artifacts.d.ts +6 -0
  47. package/chat/demo-artifacts.js +80 -0
  48. package/chat/demo-card-components.d.ts +48 -0
  49. package/chat/demo-card-components.js +66 -0
  50. package/chat/demo-cards.d.ts +32 -0
  51. package/chat/demo-cards.js +59 -0
  52. package/chat/demo-fixtures.d.ts +20 -0
  53. package/chat/demo-fixtures.js +113 -0
  54. package/chat/demo-script.d.ts +6 -0
  55. package/chat/demo-script.js +237 -0
  56. package/chat/demo.css +52 -0
  57. package/chat/demo.d.ts +10 -0
  58. package/chat/demo.js +28 -0
  59. package/chat/followups.d.ts +41 -0
  60. package/chat/followups.js +55 -0
  61. package/chat/greeting.d.ts +11 -0
  62. package/chat/greeting.js +21 -0
  63. package/chat/index.d.ts +37 -0
  64. package/chat/index.js +90 -0
  65. package/chat/placement.d.ts +48 -0
  66. package/chat/placement.js +39 -0
  67. package/chat/queries.d.ts +18 -0
  68. package/chat/queries.js +26 -0
  69. package/chat/registry.d.ts +25 -0
  70. package/chat/registry.js +9 -0
  71. package/chat/registry.json.d.ts +74 -0
  72. package/chat/registry.json.js +11 -0
  73. package/chat/server.d.ts +217 -0
  74. package/chat/server.js +488 -0
  75. package/chat/sim.d.ts +71 -0
  76. package/chat/sim.js +125 -0
  77. package/chat/starters.d.ts +15 -0
  78. package/chat/starters.js +38 -0
  79. package/chat/suggestions.d.ts +22 -0
  80. package/chat/suggestions.js +9 -0
  81. package/chat/threads.d.ts +73 -0
  82. package/chat/threads.js +270 -0
  83. package/chat/transport.d.ts +49 -0
  84. package/chat/transport.js +105 -0
  85. package/chat/types.d.ts +246 -0
  86. package/chat/types.js +18 -0
  87. package/chat/upstash.d.ts +63 -0
  88. package/chat/upstash.js +147 -0
  89. package/chat/useChat.d.ts +64 -0
  90. package/chat/useChat.js +241 -0
  91. package/cli/templates/chat/app/api/chat/feedback/route.d.ts +3 -0
  92. package/cli/templates/chat/app/api/chat/followups/route.d.ts +3 -0
  93. package/cli/templates/chat/app/api/chat/guardrails.d.ts +10 -0
  94. package/cli/templates/chat/app/api/chat/route.d.ts +4 -0
  95. package/cli/templates/chat/components/chat/ChatMount.d.ts +1 -0
  96. package/cli/templates/chat/components/chat/models.d.ts +11 -0
  97. package/components/AgentRail/AgentRail.css +14 -5
  98. package/components/AgentRail/AgentRail.d.ts +2 -0
  99. package/components/AgentRail/AgentRail.js +3 -2
  100. package/components/ArtifactCard/ArtifactCard.css +106 -0
  101. package/components/ArtifactCard/ArtifactCard.d.ts +27 -0
  102. package/components/ArtifactCard/ArtifactCard.js +29 -0
  103. package/components/ArtifactPanel/ArtifactPanel.css +159 -0
  104. package/components/ArtifactPanel/ArtifactPanel.d.ts +70 -0
  105. package/components/ArtifactPanel/ArtifactPanel.js +131 -0
  106. package/components/ShaderField/ShaderField.d.ts +3 -2
  107. package/components/ShaderField/useShaderField.d.ts +2 -1
  108. package/components/ShaderField/useShaderField.js +6 -6
  109. package/components/ThreadPanel/ThreadPanel.css +87 -33
  110. package/components/ThreadPanel/ThreadPanel.js +21 -10
  111. package/components/registry.json +16 -0
  112. package/components/registry.json.d.ts +16 -0
  113. package/components/registry.json.js +1 -1
  114. package/fonts/material-symbols.css +2 -1
  115. package/index.d.ts +2 -0
  116. package/index.js +4 -0
  117. package/package.json +39 -2
  118. package/tokens/presets/coral.css +18 -2
  119. package/tokens/presets/forest.css +18 -2
  120. package/tokens/presets/gold.css +18 -2
  121. package/tokens/presets/mono.css +18 -2
  122. package/tokens/presets/pink.css +18 -2
  123. package/tokens/presets/terminal.css +18 -2
  124. package/tokens/presets/violet.css +18 -2
  125. package/tokens/presets/warm.css +18 -2
  126. package/tokens/presets/zest.css +18 -2
  127. package/tokens/registry.json +6 -0
  128. package/tokens/registry.json.d.ts +6 -0
  129. package/tokens/registry.json.js +1 -1
  130. package/tokens/tokens-dark.css +10 -0
  131. package/tokens/tokens-light.css +10 -0
@@ -0,0 +1,217 @@
1
+ import { default as Anthropic } from '@anthropic-ai/sdk';
2
+ import { ChatCard, ChatFeedbackVerdict, ChatModelOption } from './types';
3
+ /** What a tool hands back: text for the model, and optionally a card for the visitor. */
4
+ export interface ChatToolResult {
5
+ /** The tool result the model reads. */
6
+ text: string;
7
+ /** Rich content streamed to the widget as a `card` event, drawn by the provider's renderers. */
8
+ card?: ChatCard;
9
+ }
10
+ /** One deterministic tool the model may call. */
11
+ export interface ChatTool {
12
+ /** The Anthropic tool definition: name, description, input schema. */
13
+ definition: Anthropic.Messages.Tool;
14
+ /** Runs the tool. Return a string for the model, or a result with a card for the visitor too. Never throw for bad input: return an error string the model can recover from. */
15
+ execute: (input: Record<string, unknown>) => string | ChatToolResult | Promise<string | ChatToolResult>;
16
+ /** The trace point shown while the round runs, e.g. "Checked the Button prop contract". */
17
+ tracePoint?: (input: Record<string, unknown>) => string;
18
+ }
19
+ /**
20
+ * How much of the day's budget remains, as a model policy: `open` means the
21
+ * default model serves, `reduced` means the budget model is the default (the
22
+ * better one stays selectable), `locked` means only the budget model serves.
23
+ */
24
+ export type ModelTier = 'open' | 'reduced' | 'locked';
25
+ export type GuardrailVerdict = {
26
+ allowed: true;
27
+ tier: ModelTier;
28
+ } | {
29
+ allowed: false;
30
+ notice: string;
31
+ };
32
+ /** Anthropic's usage block, narrowed to the fields a spend estimate needs. */
33
+ export interface TokenUsage {
34
+ input_tokens?: number | null;
35
+ output_tokens?: number | null;
36
+ cache_creation_input_tokens?: number | null;
37
+ cache_read_input_tokens?: number | null;
38
+ }
39
+ /** One logged exchange: what was asked, what came back, and the numbers. */
40
+ export interface ExchangeLog {
41
+ /** Minted per request and streamed to the widget, so a feedback verdict can be joined back to this line. */
42
+ id: string;
43
+ question: string;
44
+ answer: string;
45
+ /** The sanitised context the request carried, or null. */
46
+ path: string | null;
47
+ /** The model id that served, absent on guardrail notices. */
48
+ model?: string;
49
+ usage?: TokenUsage;
50
+ /** Milliseconds from request to the stream closing. */
51
+ latencyMs: number;
52
+ /** Milliseconds to the first response text, what the visitor feels. */
53
+ firstTextMs: number | null;
54
+ /** True when the answer is a guardrail notice, not a model response. */
55
+ notice: boolean;
56
+ /** The opaque per-visitor key. */
57
+ visitor: string;
58
+ }
59
+ /**
60
+ * The hooks the handlers call around a request. Every member is optional
61
+ * and every one fails open: a missing hook means no limit, no log, no
62
+ * tiering. `rift-ds/chat/upstash` implements the set over Redis.
63
+ */
64
+ export interface ChatGuardrails {
65
+ /** Rate limits and the daily breaker. Return a notice to answer with instead of calling the model. */
66
+ check?: (request: Request) => Promise<GuardrailVerdict>;
67
+ /** A stable, opaque key for the visitor (a salted hash, never an address). */
68
+ visitorKey?: (request: Request) => Promise<string> | string;
69
+ /** Called with the real token counts after every model call. */
70
+ onUsage?: (usage: TokenUsage, modelId: string) => Promise<void>;
71
+ /** Called once per exchange. Its presence is what makes the handler stream an `exchange` id, and so what shows the thumbs. */
72
+ onExchange?: (entry: ExchangeLog) => Promise<void>;
73
+ /** Per-visitor limit for the follow-ups handler. */
74
+ checkFollowups?: (request: Request) => Promise<boolean>;
75
+ /** Per-visitor limit for the feedback handler. */
76
+ checkFeedback?: (request: Request) => Promise<boolean>;
77
+ /** Stores one verdict per exchange id. */
78
+ onFeedback?: (exchangeId: string, verdict: ChatFeedbackVerdict, visitor: string) => Promise<void>;
79
+ }
80
+ export interface ChatLimits {
81
+ /** Turns kept from the client's history. Older context is dropped. */
82
+ maxTurns: number;
83
+ /** Longest single message accepted, in characters. */
84
+ maxMessageChars: number;
85
+ /** Longest whole conversation accepted, summed across every kept turn. */
86
+ maxTotalChars: number;
87
+ /** Hard ceiling on the raw request body, rejected before it is parsed. */
88
+ maxBodyChars: number;
89
+ /** Trace points shown under the status label before the rest is dropped. */
90
+ maxTracePoints: number;
91
+ }
92
+ export declare const DEFAULT_CHAT_LIMITS: ChatLimits;
93
+ export interface ChatHandlerCopy {
94
+ /** The reply when the chat is switched off or unconfigured. */
95
+ disabled: string;
96
+ /** The reply to a message over `maxMessageChars`. */
97
+ tooLong: string;
98
+ /** The reply when the model refuses and nothing was streamed. */
99
+ refusal: string;
100
+ /** Appended when the answer hit the token cap. */
101
+ cutOff: string;
102
+ /** The first status label, proving the stream opened. */
103
+ reading: string;
104
+ /** The status label while thinking. */
105
+ thinking: string;
106
+ /** The status label while a tool round runs. */
107
+ lookingUp: string;
108
+ /** The error for a busy or overloaded model. */
109
+ busy: string;
110
+ /** The error for a rejected key. */
111
+ unauthorised: string;
112
+ /** The error for anything else before the first text. */
113
+ failed: string;
114
+ }
115
+ export declare const DEFAULT_CHAT_COPY: ChatHandlerCopy;
116
+ export type SystemBlocks = Anthropic.Messages.TextBlockParam[];
117
+ export interface ChatHandlerOptions {
118
+ /** An Anthropic client to reuse, or `apiKey` to build one from. */
119
+ client?: Anthropic;
120
+ apiKey?: string;
121
+ /** The off switch. Defaults to whether a client or key is present. */
122
+ enabled?: boolean;
123
+ /**
124
+ * The system prompt, as blocks. A string is one block; a function builds
125
+ * them per request from the sanitised context. Put `cache_control` on the
126
+ * block that holds your corpus, and nothing volatile before it.
127
+ */
128
+ system: string | SystemBlocks | ((context: {
129
+ path: string | null;
130
+ }) => string | SystemBlocks);
131
+ /**
132
+ * An uncached trailing block built from the request's context, after the
133
+ * cache breakpoint. Defaults to naming the page; return null for none.
134
+ */
135
+ contextBlock?: (path: string) => string | null;
136
+ /** The models on offer. The client sends a `value`; the handler calls the matching `id`. */
137
+ models: ChatModelOption[];
138
+ /** The wire value that serves when the budget has headroom and the visitor has not chosen. Defaults to the first model. */
139
+ defaultModel?: string;
140
+ /** The wire value that serves once the budget steps down, and the only one past the lock. Defaults to `defaultModel`. */
141
+ budgetModel?: string;
142
+ tools?: ChatTool[];
143
+ /** Model calls per exchange: the first pass plus tool rounds. The last allowed pass withholds the tools. */
144
+ maxModelCalls?: number;
145
+ /** Caps thinking and response text together. */
146
+ maxTokens?: number;
147
+ /** Adaptive thinking's effort dial, for models that take it. */
148
+ effort?: 'low' | 'medium' | 'high';
149
+ guardrails?: ChatGuardrails;
150
+ limits?: Partial<ChatLimits>;
151
+ copy?: Partial<ChatHandlerCopy>;
152
+ /** Turns the request's raw `path` into context, or null to drop it. The default accepts lowercase slug paths only. */
153
+ sanitiseContext?: (value: unknown) => string | null;
154
+ /** Keeps a fire-and-forget promise alive on platforms that end work with the response. */
155
+ waitUntil?: (promise: Promise<unknown>) => void;
156
+ }
157
+ /**
158
+ * The request's context, sanitised as untrusted input: it lands in a system
159
+ * block, a stronger position than the user turn. Lowercase slug segments
160
+ * only, capped short; nothing expressible in that alphabet can carry an
161
+ * instruction. Anything else is dropped, never rejected.
162
+ */
163
+ export declare function sanitisePath(value: unknown): string | null;
164
+ /**
165
+ * The chat handler: `(request) => Response`, streaming NDJSON `ChatEvent`s.
166
+ */
167
+ export declare function createChatHandler(options: ChatHandlerOptions): (request: Request) => Promise<Response>;
168
+ export interface FollowupsHandlerOptions {
169
+ client?: Anthropic;
170
+ apiKey?: string;
171
+ enabled?: boolean;
172
+ /** The model id that writes the questions. A small one: the job is three short lines. */
173
+ model: string;
174
+ /**
175
+ * What the chat is about, in a phrase the prompt can use: "the Acme
176
+ * workspace app and its documentation". Ignored when `system` is given.
177
+ */
178
+ about?: string;
179
+ /** A complete system prompt, replacing the built-in one. */
180
+ system?: string;
181
+ /** Example questions in the voice wanted, shown to the model. */
182
+ examples?: string[];
183
+ guardrails?: Pick<ChatGuardrails, 'checkFollowups' | 'onUsage'>;
184
+ /** Chips shown. */
185
+ wanted?: number;
186
+ /** Candidates asked for, so a few long ones still leave a full row. */
187
+ candidates?: number;
188
+ /** Cap on the upstream call, inside the widget's own wait. */
189
+ timeoutMs?: number;
190
+ }
191
+ /** The built-in follow-ups prompt. */
192
+ export declare function followupsSystemPrompt({ about, candidates, examples, }: {
193
+ about: string;
194
+ candidates: number;
195
+ examples: string[];
196
+ }): string;
197
+ /**
198
+ * The model's lines to the chips that are safe to show: plain text, one
199
+ * short question each, no duplicates, at most `wanted`. Anything that does
200
+ * not fit the shape is dropped rather than repaired.
201
+ */
202
+ export declare function parseFollowups(text: string, wanted?: number): string[];
203
+ /**
204
+ * The follow-ups handler: POST `{ question, answer }`, respond
205
+ * `{ suggestions: string[] }`, empty on every failure. A second call rather
206
+ * than part of the answer's stream, because the questions are written from
207
+ * the completed answer.
208
+ */
209
+ export declare function createFollowupsHandler(options: FollowupsHandlerOptions): (request: Request) => Promise<Response>;
210
+ /**
211
+ * The feedback handler: POST `{ id, verdict }`, respond 204. The id is never
212
+ * trusted to exist; a verdict for an id no exchange used is a write nothing
213
+ * will join against, so validation is a shape check, not a lookup.
214
+ */
215
+ export declare function createFeedbackHandler(options?: {
216
+ guardrails?: Pick<ChatGuardrails, 'checkFeedback' | 'onFeedback' | 'visitorKey'>;
217
+ }): (request: Request) => Promise<Response>;