@invergent/agent-chat-react 1.5.5 → 1.5.7

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/index.cjs CHANGED
@@ -19,9 +19,9 @@ var reactUseControllableState = require('@radix-ui/react-use-controllable-state'
19
19
  var shiki = require('shiki');
20
20
  var diff = require('diff');
21
21
  var Ansi = require('ansi-to-react');
22
- var tokenlens = require('tokenlens');
23
22
  var cmdk = require('cmdk');
24
23
  var nanoid = require('nanoid');
24
+ var tokenlens = require('tokenlens');
25
25
  require('pdfjs-dist/web/pdf_viewer.css');
26
26
  var dateFns = require('date-fns');
27
27
 
@@ -3947,7 +3947,18 @@ var ChatMessage = react.memo(function ChatMessage2({
3947
3947
  onFileSelect
3948
3948
  }) {
3949
3949
  if (message.role === "user") {
3950
- return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "user", children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { children: message.content }) });
3950
+ return /* @__PURE__ */ jsxRuntime.jsx(Message, { from: "user", children: /* @__PURE__ */ jsxRuntime.jsxs(MessageContent, { children: [
3951
+ message.content,
3952
+ message.images && message.images.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 mt-2", children: message.images.map((img, i) => /* @__PURE__ */ jsxRuntime.jsx(
3953
+ "img",
3954
+ {
3955
+ src: img.data,
3956
+ alt: "Attached",
3957
+ className: "max-w-64 max-h-48 rounded-lg border border-border object-contain"
3958
+ },
3959
+ i
3960
+ )) })
3961
+ ] }) });
3951
3962
  }
3952
3963
  return /* @__PURE__ */ jsxRuntime.jsx(AssistantMessage, { message, isLast, onFileSelect });
3953
3964
  });
@@ -3974,487 +3985,159 @@ function AssistantMessage({
3974
3985
  ] }) });
3975
3986
  }
3976
3987
 
3977
- // src/components/ui/hover-card.tsx
3988
+ // src/components/ui/command.tsx
3978
3989
  init_utils();
3979
- function HoverCard({
3990
+
3991
+ // src/components/ui/input-group.tsx
3992
+ init_utils();
3993
+ function InputGroup({ className, ...props }) {
3994
+ return /* @__PURE__ */ jsxRuntime.jsx(
3995
+ "div",
3996
+ {
3997
+ "data-slot": "input-group",
3998
+ role: "group",
3999
+ className: cn(
4000
+ "group/input-group relative flex h-10 w-full min-w-0 items-center rounded-none border border-transparent border-b-input bg-transparent transition-[color,border-color] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-data-[align=block-end]:rounded-none has-data-[align=block-start]:rounded-none has-[[data-slot=input-group-control]:focus-visible]:border-b-ring has-[[data-slot][aria-invalid=true]]:border-b-destructive has-[textarea]:rounded-none has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:has-[[data-slot][aria-invalid=true]]:border-b-destructive/50 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3",
4001
+ className
4002
+ ),
4003
+ ...props
4004
+ }
4005
+ );
4006
+ }
4007
+ var inputGroupAddonVariants = classVarianceAuthority.cva(
4008
+ "flex h-auto cursor-text items-center justify-center gap-2 py-2 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 **:data-[slot=kbd]:rounded-none **:data-[slot=kbd]:bg-muted-foreground/10 **:data-[slot=kbd]:px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
4009
+ {
4010
+ variants: {
4011
+ align: {
4012
+ "inline-start": "order-first",
4013
+ "inline-end": "order-last",
4014
+ "block-start": "order-first w-full justify-start pt-3 group-has-[>input]/input-group:pt-3.5 [.border-b]:pb-3.5",
4015
+ "block-end": "order-last w-full justify-start pb-3 group-has-[>input]/input-group:pb-3.5 [.border-t]:pt-3.5"
4016
+ }
4017
+ },
4018
+ defaultVariants: {
4019
+ align: "inline-start"
4020
+ }
4021
+ }
4022
+ );
4023
+ function InputGroupAddon({
4024
+ className,
4025
+ align = "inline-start",
3980
4026
  ...props
3981
4027
  }) {
3982
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.HoverCard.Root, { "data-slot": "hover-card", ...props });
4028
+ return /* @__PURE__ */ jsxRuntime.jsx(
4029
+ "div",
4030
+ {
4031
+ role: "group",
4032
+ "data-slot": "input-group-addon",
4033
+ "data-align": align,
4034
+ className: cn(inputGroupAddonVariants({ align }), className),
4035
+ onClick: (e) => {
4036
+ if (e.target.closest("button")) {
4037
+ return;
4038
+ }
4039
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
4040
+ },
4041
+ ...props
4042
+ }
4043
+ );
3983
4044
  }
3984
- function HoverCardTrigger({
4045
+ var inputGroupButtonVariants = classVarianceAuthority.cva(
4046
+ "flex items-center gap-2 rounded-none text-sm shadow-none",
4047
+ {
4048
+ variants: {
4049
+ size: {
4050
+ xs: "h-6 gap-1 rounded-none px-1.5 text-xs [&>svg:not([class*='size-'])]:size-3.5",
4051
+ sm: "",
4052
+ "icon-xs": "size-6 p-0 text-xs has-[>svg]:p-0",
4053
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0"
4054
+ }
4055
+ },
4056
+ defaultVariants: {
4057
+ size: "xs"
4058
+ }
4059
+ }
4060
+ );
4061
+ function InputGroupButton({
4062
+ className,
4063
+ type = "button",
4064
+ variant = "ghost",
4065
+ size = "xs",
3985
4066
  ...props
3986
4067
  }) {
3987
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.HoverCard.Trigger, { "data-slot": "hover-card-trigger", ...props });
4068
+ return /* @__PURE__ */ jsxRuntime.jsx(
4069
+ Button,
4070
+ {
4071
+ type,
4072
+ "data-size": size,
4073
+ variant,
4074
+ className: cn(inputGroupButtonVariants({ size }), className),
4075
+ ...props
4076
+ }
4077
+ );
3988
4078
  }
3989
- function HoverCardContent({
4079
+ function InputGroupTextarea({
3990
4080
  className,
3991
- align = "center",
3992
- sideOffset = 4,
3993
4081
  ...props
3994
4082
  }) {
3995
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.HoverCard.Portal, { "data-slot": "hover-card-portal", children: /* @__PURE__ */ jsxRuntime.jsx(
3996
- radixUi.HoverCard.Content,
4083
+ return /* @__PURE__ */ jsxRuntime.jsx(
4084
+ Textarea,
3997
4085
  {
3998
- "data-slot": "hover-card-content",
3999
- align,
4000
- sideOffset,
4086
+ "data-slot": "input-group-control",
4001
4087
  className: cn(
4002
- "z-50 w-72 origin-(--radix-hover-card-content-transform-origin) bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
4088
+ "flex-1 resize-none border-0 bg-transparent py-2.5 ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent",
4003
4089
  className
4004
4090
  ),
4005
4091
  ...props
4006
4092
  }
4007
- ) });
4093
+ );
4008
4094
  }
4009
-
4010
- // src/components/ui/progress.tsx
4011
- init_utils();
4012
- function Progress({
4095
+ function Command({
4013
4096
  className,
4014
- value,
4015
4097
  ...props
4016
4098
  }) {
4017
4099
  return /* @__PURE__ */ jsxRuntime.jsx(
4018
- radixUi.Progress.Root,
4100
+ cmdk.Command,
4019
4101
  {
4020
- "data-slot": "progress",
4102
+ "data-slot": "command",
4021
4103
  className: cn(
4022
- "relative flex h-0.5 w-full items-center overflow-x-hidden rounded-none bg-muted",
4104
+ "flex size-full flex-col overflow-hidden bg-popover text-popover-foreground",
4023
4105
  className
4024
4106
  ),
4025
- ...props,
4026
- children: /* @__PURE__ */ jsxRuntime.jsx(
4027
- radixUi.Progress.Indicator,
4028
- {
4029
- "data-slot": "progress-indicator",
4030
- className: "size-full flex-1 bg-primary transition-all",
4031
- style: { transform: `translateX(-${100 - (value || 0)}%)` }
4032
- }
4033
- )
4107
+ ...props
4034
4108
  }
4035
4109
  );
4036
4110
  }
4037
-
4038
- // src/components/ai-elements/context.tsx
4039
- init_utils();
4040
- var PERCENT_MAX = 100;
4041
- var ICON_RADIUS = 10;
4042
- var ICON_VIEWBOX = 24;
4043
- var ICON_CENTER = 12;
4044
- var ICON_STROKE_WIDTH = 2;
4045
- var ContextContext = react.createContext(null);
4046
- var useContextValue = () => {
4047
- const context = react.useContext(ContextContext);
4048
- if (!context) {
4049
- throw new Error("Context components must be used within Context");
4050
- }
4051
- return context;
4052
- };
4053
- var Context = ({
4054
- usedTokens,
4055
- maxTokens,
4056
- usage,
4057
- modelId,
4111
+ function CommandList({
4112
+ className,
4058
4113
  ...props
4059
- }) => {
4060
- const contextValue = react.useMemo(
4061
- () => ({ maxTokens, modelId, usage, usedTokens }),
4062
- [maxTokens, modelId, usage, usedTokens]
4063
- );
4064
- return /* @__PURE__ */ jsxRuntime.jsx(ContextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(HoverCard, { closeDelay: 0, openDelay: 0, ...props }) });
4065
- };
4066
- var ContextIcon = () => {
4067
- const { usedTokens, maxTokens } = useContextValue();
4068
- const circumference = 2 * Math.PI * ICON_RADIUS;
4069
- const usedPercent = usedTokens / maxTokens;
4070
- const dashOffset = circumference * (1 - usedPercent);
4071
- return /* @__PURE__ */ jsxRuntime.jsxs(
4072
- "svg",
4114
+ }) {
4115
+ return /* @__PURE__ */ jsxRuntime.jsx(
4116
+ cmdk.Command.List,
4073
4117
  {
4074
- "aria-label": "Model context usage",
4075
- height: "20",
4076
- role: "img",
4077
- style: { color: "currentcolor" },
4078
- viewBox: `0 0 ${ICON_VIEWBOX} ${ICON_VIEWBOX}`,
4079
- width: "20",
4080
- children: [
4081
- /* @__PURE__ */ jsxRuntime.jsx(
4082
- "circle",
4083
- {
4084
- cx: ICON_CENTER,
4085
- cy: ICON_CENTER,
4086
- fill: "none",
4087
- opacity: "0.25",
4088
- r: ICON_RADIUS,
4089
- stroke: "currentColor",
4090
- strokeWidth: ICON_STROKE_WIDTH
4091
- }
4092
- ),
4093
- /* @__PURE__ */ jsxRuntime.jsx(
4094
- "circle",
4095
- {
4096
- cx: ICON_CENTER,
4097
- cy: ICON_CENTER,
4098
- fill: "none",
4099
- opacity: "0.7",
4100
- r: ICON_RADIUS,
4101
- stroke: "currentColor",
4102
- strokeDasharray: `${circumference} ${circumference}`,
4103
- strokeDashoffset: dashOffset,
4104
- strokeLinecap: "round",
4105
- strokeWidth: ICON_STROKE_WIDTH,
4106
- style: { transform: "rotate(-90deg)", transformOrigin: "center" }
4107
- }
4108
- )
4109
- ]
4118
+ "data-slot": "command-list",
4119
+ className: cn(
4120
+ "no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none",
4121
+ className
4122
+ ),
4123
+ ...props
4110
4124
  }
4111
4125
  );
4112
- };
4113
- var ContextTrigger = ({ children, ...props }) => {
4114
- return /* @__PURE__ */ jsxRuntime.jsx(HoverCardTrigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ContextIcon, {}) }) });
4115
- };
4116
- var ContextContent = ({
4126
+ }
4127
+ function CommandEmpty({
4117
4128
  className,
4118
4129
  ...props
4119
- }) => /* @__PURE__ */ jsxRuntime.jsx(
4120
- HoverCardContent,
4121
- {
4122
- className: cn("min-w-60 divide-y overflow-hidden p-0", className),
4123
- ...props
4124
- }
4125
- );
4126
- var ContextContentHeader = ({
4127
- children,
4128
- className,
4129
- ...props
4130
- }) => {
4131
- const { usedTokens, maxTokens } = useContextValue();
4132
- const usedPercent = usedTokens / maxTokens;
4133
- const displayPct = new Intl.NumberFormat("en-US", {
4134
- maximumFractionDigits: 1,
4135
- style: "percent"
4136
- }).format(usedPercent);
4137
- const used = new Intl.NumberFormat("en-US", {
4138
- notation: "compact"
4139
- }).format(usedTokens);
4140
- const total = new Intl.NumberFormat("en-US", {
4141
- notation: "compact"
4142
- }).format(maxTokens);
4143
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full space-y-2 p-3", className), ...props, children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4144
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 text-xs", children: [
4145
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: displayPct }),
4146
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: " text-muted-foreground", children: [
4147
- used,
4148
- " / ",
4149
- total
4150
- ] })
4151
- ] }),
4152
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx(Progress, { className: "bg-muted", value: usedPercent * PERCENT_MAX }) })
4153
- ] }) });
4154
- };
4155
- var ContextContentBody = ({
4156
- children,
4157
- className,
4158
- ...props
4159
- }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full p-3", className), ...props, children });
4160
- var TokensWithCost = ({
4161
- tokens,
4162
- costText
4163
- }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
4164
- tokens === void 0 ? "\u2014" : new Intl.NumberFormat("en-US", {
4165
- notation: "compact"
4166
- }).format(tokens),
4167
- costText ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-muted-foreground", children: [
4168
- "\u2022 ",
4169
- costText
4170
- ] }) : null
4171
- ] });
4172
- var ContextInputUsage = ({
4173
- className,
4174
- children,
4175
- ...props
4176
- }) => {
4177
- const { usage, modelId } = useContextValue();
4178
- const inputTokens = usage?.inputTokens ?? 0;
4179
- if (children) {
4180
- return children;
4181
- }
4182
- if (!inputTokens) {
4183
- return null;
4184
- }
4185
- const inputCost = modelId ? tokenlens.getUsage({
4186
- modelId,
4187
- usage: { input: inputTokens, output: 0 }
4188
- }).costUSD?.totalUSD : void 0;
4189
- const inputCostText = new Intl.NumberFormat("en-US", {
4190
- currency: "USD",
4191
- style: "currency"
4192
- }).format(inputCost ?? 0);
4193
- return /* @__PURE__ */ jsxRuntime.jsxs(
4194
- "div",
4195
- {
4196
- className: cn("flex items-center justify-between text-xs", className),
4197
- ...props,
4198
- children: [
4199
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Input" }),
4200
- /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: inputCostText, tokens: inputTokens })
4201
- ]
4202
- }
4203
- );
4204
- };
4205
- var ContextOutputUsage = ({
4206
- className,
4207
- children,
4208
- ...props
4209
- }) => {
4210
- const { usage, modelId } = useContextValue();
4211
- const outputTokens = usage?.outputTokens ?? 0;
4212
- if (children) {
4213
- return children;
4214
- }
4215
- if (!outputTokens) {
4216
- return null;
4217
- }
4218
- const outputCost = modelId ? tokenlens.getUsage({
4219
- modelId,
4220
- usage: { input: 0, output: outputTokens }
4221
- }).costUSD?.totalUSD : void 0;
4222
- const outputCostText = new Intl.NumberFormat("en-US", {
4223
- currency: "USD",
4224
- style: "currency"
4225
- }).format(outputCost ?? 0);
4226
- return /* @__PURE__ */ jsxRuntime.jsxs(
4227
- "div",
4228
- {
4229
- className: cn("flex items-center justify-between text-xs", className),
4230
- ...props,
4231
- children: [
4232
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Output" }),
4233
- /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: outputCostText, tokens: outputTokens })
4234
- ]
4235
- }
4236
- );
4237
- };
4238
- var ContextReasoningUsage = ({
4239
- className,
4240
- children,
4241
- ...props
4242
- }) => {
4243
- const { usage, modelId } = useContextValue();
4244
- const reasoningTokens = usage?.reasoningTokens ?? 0;
4245
- if (children) {
4246
- return children;
4247
- }
4248
- if (!reasoningTokens) {
4249
- return null;
4250
- }
4251
- const reasoningCost = modelId ? tokenlens.getUsage({
4252
- modelId,
4253
- usage: { reasoningTokens }
4254
- }).costUSD?.totalUSD : void 0;
4255
- const reasoningCostText = new Intl.NumberFormat("en-US", {
4256
- currency: "USD",
4257
- style: "currency"
4258
- }).format(reasoningCost ?? 0);
4259
- return /* @__PURE__ */ jsxRuntime.jsxs(
4260
- "div",
4261
- {
4262
- className: cn("flex items-center justify-between text-xs", className),
4263
- ...props,
4264
- children: [
4265
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Reasoning" }),
4266
- /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: reasoningCostText, tokens: reasoningTokens })
4267
- ]
4268
- }
4269
- );
4270
- };
4271
- var ContextCacheUsage = ({
4272
- className,
4273
- children,
4274
- ...props
4275
- }) => {
4276
- const { usage, modelId } = useContextValue();
4277
- const cacheTokens = usage?.cachedInputTokens ?? 0;
4278
- if (children) {
4279
- return children;
4280
- }
4281
- if (!cacheTokens) {
4282
- return null;
4283
- }
4284
- const cacheCost = modelId ? tokenlens.getUsage({
4285
- modelId,
4286
- usage: { cacheReads: cacheTokens, input: 0, output: 0 }
4287
- }).costUSD?.totalUSD : void 0;
4288
- const cacheCostText = new Intl.NumberFormat("en-US", {
4289
- currency: "USD",
4290
- style: "currency"
4291
- }).format(cacheCost ?? 0);
4292
- return /* @__PURE__ */ jsxRuntime.jsxs(
4293
- "div",
4294
- {
4295
- className: cn("flex items-center justify-between text-xs", className),
4296
- ...props,
4297
- children: [
4298
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Cache" }),
4299
- /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: cacheCostText, tokens: cacheTokens })
4300
- ]
4301
- }
4302
- );
4303
- };
4304
-
4305
- // src/components/ui/command.tsx
4306
- init_utils();
4307
-
4308
- // src/components/ui/input-group.tsx
4309
- init_utils();
4310
- function InputGroup({ className, ...props }) {
4311
- return /* @__PURE__ */ jsxRuntime.jsx(
4312
- "div",
4313
- {
4314
- "data-slot": "input-group",
4315
- role: "group",
4316
- className: cn(
4317
- "group/input-group relative flex h-10 w-full min-w-0 items-center rounded-none border border-transparent border-b-input bg-transparent transition-[color,border-color] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-data-[align=block-end]:rounded-none has-data-[align=block-start]:rounded-none has-[[data-slot=input-group-control]:focus-visible]:border-b-ring has-[[data-slot][aria-invalid=true]]:border-b-destructive has-[textarea]:rounded-none has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:has-[[data-slot][aria-invalid=true]]:border-b-destructive/50 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3",
4318
- className
4319
- ),
4320
- ...props
4321
- }
4322
- );
4323
- }
4324
- var inputGroupAddonVariants = classVarianceAuthority.cva(
4325
- "flex h-auto cursor-text items-center justify-center gap-2 py-2 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 **:data-[slot=kbd]:rounded-none **:data-[slot=kbd]:bg-muted-foreground/10 **:data-[slot=kbd]:px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
4326
- {
4327
- variants: {
4328
- align: {
4329
- "inline-start": "order-first",
4330
- "inline-end": "order-last",
4331
- "block-start": "order-first w-full justify-start pt-3 group-has-[>input]/input-group:pt-3.5 [.border-b]:pb-3.5",
4332
- "block-end": "order-last w-full justify-start pb-3 group-has-[>input]/input-group:pb-3.5 [.border-t]:pt-3.5"
4333
- }
4334
- },
4335
- defaultVariants: {
4336
- align: "inline-start"
4337
- }
4338
- }
4339
- );
4340
- function InputGroupAddon({
4341
- className,
4342
- align = "inline-start",
4343
- ...props
4344
- }) {
4345
- return /* @__PURE__ */ jsxRuntime.jsx(
4346
- "div",
4347
- {
4348
- role: "group",
4349
- "data-slot": "input-group-addon",
4350
- "data-align": align,
4351
- className: cn(inputGroupAddonVariants({ align }), className),
4352
- onClick: (e) => {
4353
- if (e.target.closest("button")) {
4354
- return;
4355
- }
4356
- e.currentTarget.parentElement?.querySelector("input")?.focus();
4357
- },
4358
- ...props
4359
- }
4360
- );
4361
- }
4362
- var inputGroupButtonVariants = classVarianceAuthority.cva(
4363
- "flex items-center gap-2 rounded-none text-sm shadow-none",
4364
- {
4365
- variants: {
4366
- size: {
4367
- xs: "h-6 gap-1 rounded-none px-1.5 text-xs [&>svg:not([class*='size-'])]:size-3.5",
4368
- sm: "",
4369
- "icon-xs": "size-6 p-0 text-xs has-[>svg]:p-0",
4370
- "icon-sm": "size-8 p-0 has-[>svg]:p-0"
4371
- }
4372
- },
4373
- defaultVariants: {
4374
- size: "xs"
4375
- }
4376
- }
4377
- );
4378
- function InputGroupButton({
4379
- className,
4380
- type = "button",
4381
- variant = "ghost",
4382
- size = "xs",
4383
- ...props
4384
- }) {
4385
- return /* @__PURE__ */ jsxRuntime.jsx(
4386
- Button,
4387
- {
4388
- type,
4389
- "data-size": size,
4390
- variant,
4391
- className: cn(inputGroupButtonVariants({ size }), className),
4392
- ...props
4393
- }
4394
- );
4395
- }
4396
- function InputGroupTextarea({
4397
- className,
4398
- ...props
4399
- }) {
4400
- return /* @__PURE__ */ jsxRuntime.jsx(
4401
- Textarea,
4402
- {
4403
- "data-slot": "input-group-control",
4404
- className: cn(
4405
- "flex-1 resize-none border-0 bg-transparent py-2.5 ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent",
4406
- className
4407
- ),
4408
- ...props
4409
- }
4410
- );
4411
- }
4412
- function Command({
4413
- className,
4414
- ...props
4415
- }) {
4416
- return /* @__PURE__ */ jsxRuntime.jsx(
4417
- cmdk.Command,
4418
- {
4419
- "data-slot": "command",
4420
- className: cn(
4421
- "flex size-full flex-col overflow-hidden bg-popover text-popover-foreground",
4422
- className
4423
- ),
4424
- ...props
4425
- }
4426
- );
4427
- }
4428
- function CommandList({
4429
- className,
4430
- ...props
4431
- }) {
4432
- return /* @__PURE__ */ jsxRuntime.jsx(
4433
- cmdk.Command.List,
4434
- {
4435
- "data-slot": "command-list",
4436
- className: cn(
4437
- "no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none",
4438
- className
4439
- ),
4440
- ...props
4441
- }
4442
- );
4443
- }
4444
- function CommandEmpty({
4445
- className,
4446
- ...props
4447
- }) {
4448
- return /* @__PURE__ */ jsxRuntime.jsx(
4449
- cmdk.Command.Empty,
4450
- {
4451
- "data-slot": "command-empty",
4452
- className: cn("py-6 text-center text-sm", className),
4453
- ...props
4454
- }
4455
- );
4456
- }
4457
- function CommandGroup({
4130
+ }) {
4131
+ return /* @__PURE__ */ jsxRuntime.jsx(
4132
+ cmdk.Command.Empty,
4133
+ {
4134
+ "data-slot": "command-empty",
4135
+ className: cn("py-6 text-center text-sm", className),
4136
+ ...props
4137
+ }
4138
+ );
4139
+ }
4140
+ function CommandGroup({
4458
4141
  className,
4459
4142
  ...props
4460
4143
  }) {
@@ -4548,6 +4231,39 @@ function DropdownMenuItem({
4548
4231
  );
4549
4232
  }
4550
4233
 
4234
+ // src/components/ui/hover-card.tsx
4235
+ init_utils();
4236
+ function HoverCard({
4237
+ ...props
4238
+ }) {
4239
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.HoverCard.Root, { "data-slot": "hover-card", ...props });
4240
+ }
4241
+ function HoverCardTrigger({
4242
+ ...props
4243
+ }) {
4244
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.HoverCard.Trigger, { "data-slot": "hover-card-trigger", ...props });
4245
+ }
4246
+ function HoverCardContent({
4247
+ className,
4248
+ align = "center",
4249
+ sideOffset = 4,
4250
+ ...props
4251
+ }) {
4252
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.HoverCard.Portal, { "data-slot": "hover-card-portal", children: /* @__PURE__ */ jsxRuntime.jsx(
4253
+ radixUi.HoverCard.Content,
4254
+ {
4255
+ "data-slot": "hover-card-content",
4256
+ align,
4257
+ sideOffset,
4258
+ className: cn(
4259
+ "z-50 w-72 origin-(--radix-hover-card-content-transform-origin) bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
4260
+ className
4261
+ ),
4262
+ ...props
4263
+ }
4264
+ ) });
4265
+ }
4266
+
4551
4267
  // src/components/ui/spinner.tsx
4552
4268
  init_utils();
4553
4269
  function Spinner({ className, ...props }) {
@@ -4586,6 +4302,15 @@ var usePromptInputController = () => {
4586
4302
  return ctx;
4587
4303
  };
4588
4304
  var useOptionalPromptInputController = () => react.useContext(PromptInputController);
4305
+ var useProviderAttachments = () => {
4306
+ const ctx = react.useContext(ProviderAttachmentsContext);
4307
+ if (!ctx) {
4308
+ throw new Error(
4309
+ "Wrap your component inside <PromptInputProvider> to use useProviderAttachments()."
4310
+ );
4311
+ }
4312
+ return ctx;
4313
+ };
4589
4314
  var useOptionalProviderAttachments = () => react.useContext(ProviderAttachmentsContext);
4590
4315
  var PromptInputProvider = ({
4591
4316
  initialInput: initialTextInput = "",
@@ -5161,95 +4886,390 @@ var PromptInputTools = ({
5161
4886
  className,
5162
4887
  ...props
5163
4888
  }) => /* @__PURE__ */ jsxRuntime.jsx(
5164
- "div",
4889
+ "div",
4890
+ {
4891
+ className: cn("flex min-w-0 items-center gap-1", className),
4892
+ ...props
4893
+ }
4894
+ );
4895
+ var PromptInputButton = ({
4896
+ variant = "ghost",
4897
+ className,
4898
+ size,
4899
+ tooltip,
4900
+ ...props
4901
+ }) => {
4902
+ const newSize = size ?? (react.Children.count(props.children) > 1 ? "sm" : "icon-sm");
4903
+ const button = /* @__PURE__ */ jsxRuntime.jsx(
4904
+ InputGroupButton,
4905
+ {
4906
+ className: cn(className),
4907
+ size: newSize,
4908
+ type: "button",
4909
+ variant,
4910
+ ...props
4911
+ }
4912
+ );
4913
+ if (!tooltip) {
4914
+ return button;
4915
+ }
4916
+ const tooltipContent = typeof tooltip === "string" ? tooltip : tooltip.content;
4917
+ const shortcut = typeof tooltip === "string" ? void 0 : tooltip.shortcut;
4918
+ const side = typeof tooltip === "string" ? "top" : tooltip.side ?? "top";
4919
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
4920
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: button }),
4921
+ /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side, children: [
4922
+ tooltipContent,
4923
+ shortcut && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 text-muted-foreground", children: shortcut })
4924
+ ] })
4925
+ ] });
4926
+ };
4927
+ var PromptInputActionMenu = (props) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu, { ...props });
4928
+ var PromptInputActionMenuTrigger = ({
4929
+ className,
4930
+ children,
4931
+ ...props
4932
+ }) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(PromptInputButton, { className, ...props, children: children ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { className: "size-4" }) }) });
4933
+ var PromptInputActionMenuContent = ({
4934
+ className,
4935
+ ...props
4936
+ }) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "start", className: cn(className), ...props });
4937
+ var PromptInputSubmit = ({
4938
+ className,
4939
+ variant = "default",
4940
+ size = "icon-sm",
4941
+ status,
4942
+ onStop,
4943
+ onClick,
4944
+ children,
4945
+ ...props
4946
+ }) => {
4947
+ const isGenerating = status === "submitted" || status === "streaming";
4948
+ let Icon = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeftIcon, { className: "size-4" });
4949
+ if (status === "submitted") {
4950
+ Icon = /* @__PURE__ */ jsxRuntime.jsx(Spinner, {});
4951
+ } else if (status === "streaming") {
4952
+ Icon = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SquareIcon, { className: "size-4" });
4953
+ } else if (status === "error") {
4954
+ Icon = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-4" });
4955
+ }
4956
+ const handleClick = react.useCallback(
4957
+ (e) => {
4958
+ if (isGenerating && onStop) {
4959
+ e.preventDefault();
4960
+ onStop();
4961
+ return;
4962
+ }
4963
+ onClick?.(e);
4964
+ },
4965
+ [isGenerating, onStop, onClick]
4966
+ );
4967
+ return /* @__PURE__ */ jsxRuntime.jsx(
4968
+ InputGroupButton,
4969
+ {
4970
+ "aria-label": isGenerating ? "Stop" : "Submit",
4971
+ className: cn(className),
4972
+ onClick: handleClick,
4973
+ size,
4974
+ type: isGenerating && onStop ? "button" : "submit",
4975
+ variant,
4976
+ ...props,
4977
+ children: children ?? Icon
4978
+ }
4979
+ );
4980
+ };
4981
+
4982
+ // src/components/ui/progress.tsx
4983
+ init_utils();
4984
+ function Progress({
4985
+ className,
4986
+ value,
4987
+ ...props
4988
+ }) {
4989
+ return /* @__PURE__ */ jsxRuntime.jsx(
4990
+ radixUi.Progress.Root,
4991
+ {
4992
+ "data-slot": "progress",
4993
+ className: cn(
4994
+ "relative flex h-0.5 w-full items-center overflow-x-hidden rounded-none bg-muted",
4995
+ className
4996
+ ),
4997
+ ...props,
4998
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4999
+ radixUi.Progress.Indicator,
5000
+ {
5001
+ "data-slot": "progress-indicator",
5002
+ className: "size-full flex-1 bg-primary transition-all",
5003
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
5004
+ }
5005
+ )
5006
+ }
5007
+ );
5008
+ }
5009
+
5010
+ // src/components/ai-elements/context.tsx
5011
+ init_utils();
5012
+ var PERCENT_MAX = 100;
5013
+ var ICON_RADIUS = 10;
5014
+ var ICON_VIEWBOX = 24;
5015
+ var ICON_CENTER = 12;
5016
+ var ICON_STROKE_WIDTH = 2;
5017
+ var ContextContext = react.createContext(null);
5018
+ var useContextValue = () => {
5019
+ const context = react.useContext(ContextContext);
5020
+ if (!context) {
5021
+ throw new Error("Context components must be used within Context");
5022
+ }
5023
+ return context;
5024
+ };
5025
+ var Context = ({
5026
+ usedTokens,
5027
+ maxTokens,
5028
+ usage,
5029
+ modelId,
5030
+ ...props
5031
+ }) => {
5032
+ const contextValue = react.useMemo(
5033
+ () => ({ maxTokens, modelId, usage, usedTokens }),
5034
+ [maxTokens, modelId, usage, usedTokens]
5035
+ );
5036
+ return /* @__PURE__ */ jsxRuntime.jsx(ContextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(HoverCard, { closeDelay: 0, openDelay: 0, ...props }) });
5037
+ };
5038
+ var ContextIcon = () => {
5039
+ const { usedTokens, maxTokens } = useContextValue();
5040
+ const circumference = 2 * Math.PI * ICON_RADIUS;
5041
+ const usedPercent = usedTokens / maxTokens;
5042
+ const dashOffset = circumference * (1 - usedPercent);
5043
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5044
+ "svg",
5045
+ {
5046
+ "aria-label": "Model context usage",
5047
+ height: "20",
5048
+ role: "img",
5049
+ style: { color: "currentcolor" },
5050
+ viewBox: `0 0 ${ICON_VIEWBOX} ${ICON_VIEWBOX}`,
5051
+ width: "20",
5052
+ children: [
5053
+ /* @__PURE__ */ jsxRuntime.jsx(
5054
+ "circle",
5055
+ {
5056
+ cx: ICON_CENTER,
5057
+ cy: ICON_CENTER,
5058
+ fill: "none",
5059
+ opacity: "0.25",
5060
+ r: ICON_RADIUS,
5061
+ stroke: "currentColor",
5062
+ strokeWidth: ICON_STROKE_WIDTH
5063
+ }
5064
+ ),
5065
+ /* @__PURE__ */ jsxRuntime.jsx(
5066
+ "circle",
5067
+ {
5068
+ cx: ICON_CENTER,
5069
+ cy: ICON_CENTER,
5070
+ fill: "none",
5071
+ opacity: "0.7",
5072
+ r: ICON_RADIUS,
5073
+ stroke: "currentColor",
5074
+ strokeDasharray: `${circumference} ${circumference}`,
5075
+ strokeDashoffset: dashOffset,
5076
+ strokeLinecap: "round",
5077
+ strokeWidth: ICON_STROKE_WIDTH,
5078
+ style: { transform: "rotate(-90deg)", transformOrigin: "center" }
5079
+ }
5080
+ )
5081
+ ]
5082
+ }
5083
+ );
5084
+ };
5085
+ var ContextTrigger = ({ children, ...props }) => {
5086
+ return /* @__PURE__ */ jsxRuntime.jsx(HoverCardTrigger, { asChild: true, children: children ?? /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "ghost", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(ContextIcon, {}) }) });
5087
+ };
5088
+ var ContextContent = ({
5089
+ className,
5090
+ ...props
5091
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
5092
+ HoverCardContent,
5165
5093
  {
5166
- className: cn("flex min-w-0 items-center gap-1", className),
5094
+ className: cn("min-w-60 divide-y overflow-hidden p-0", className),
5167
5095
  ...props
5168
5096
  }
5169
5097
  );
5170
- var PromptInputButton = ({
5171
- variant = "ghost",
5098
+ var ContextContentHeader = ({
5099
+ children,
5172
5100
  className,
5173
- size,
5174
- tooltip,
5175
5101
  ...props
5176
5102
  }) => {
5177
- const newSize = size ?? (react.Children.count(props.children) > 1 ? "sm" : "icon-sm");
5178
- const button = /* @__PURE__ */ jsxRuntime.jsx(
5179
- InputGroupButton,
5103
+ const { usedTokens, maxTokens } = useContextValue();
5104
+ const usedPercent = usedTokens / maxTokens;
5105
+ const displayPct = new Intl.NumberFormat("en-US", {
5106
+ maximumFractionDigits: 1,
5107
+ style: "percent"
5108
+ }).format(usedPercent);
5109
+ const used = new Intl.NumberFormat("en-US", {
5110
+ notation: "compact"
5111
+ }).format(usedTokens);
5112
+ const total = new Intl.NumberFormat("en-US", {
5113
+ notation: "compact"
5114
+ }).format(maxTokens);
5115
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full space-y-2 p-3", className), ...props, children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5116
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 text-xs", children: [
5117
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: displayPct }),
5118
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: " text-muted-foreground", children: [
5119
+ used,
5120
+ " / ",
5121
+ total
5122
+ ] })
5123
+ ] }),
5124
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx(Progress, { className: "bg-muted", value: usedPercent * PERCENT_MAX }) })
5125
+ ] }) });
5126
+ };
5127
+ var ContextContentBody = ({
5128
+ children,
5129
+ className,
5130
+ ...props
5131
+ }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full p-3", className), ...props, children });
5132
+ var TokensWithCost = ({
5133
+ tokens,
5134
+ costText
5135
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5136
+ tokens === void 0 ? "\u2014" : new Intl.NumberFormat("en-US", {
5137
+ notation: "compact"
5138
+ }).format(tokens),
5139
+ costText ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-muted-foreground", children: [
5140
+ "\u2022 ",
5141
+ costText
5142
+ ] }) : null
5143
+ ] });
5144
+ var ContextInputUsage = ({
5145
+ className,
5146
+ children,
5147
+ ...props
5148
+ }) => {
5149
+ const { usage, modelId } = useContextValue();
5150
+ const inputTokens = usage?.inputTokens ?? 0;
5151
+ if (children) {
5152
+ return children;
5153
+ }
5154
+ if (!inputTokens) {
5155
+ return null;
5156
+ }
5157
+ const inputCost = modelId ? tokenlens.getUsage({
5158
+ modelId,
5159
+ usage: { input: inputTokens, output: 0 }
5160
+ }).costUSD?.totalUSD : void 0;
5161
+ const inputCostText = new Intl.NumberFormat("en-US", {
5162
+ currency: "USD",
5163
+ style: "currency"
5164
+ }).format(inputCost ?? 0);
5165
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5166
+ "div",
5180
5167
  {
5181
- className: cn(className),
5182
- size: newSize,
5183
- type: "button",
5184
- variant,
5185
- ...props
5168
+ className: cn("flex items-center justify-between text-xs", className),
5169
+ ...props,
5170
+ children: [
5171
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Input" }),
5172
+ /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: inputCostText, tokens: inputTokens })
5173
+ ]
5186
5174
  }
5187
5175
  );
5188
- if (!tooltip) {
5189
- return button;
5190
- }
5191
- const tooltipContent = typeof tooltip === "string" ? tooltip : tooltip.content;
5192
- const shortcut = typeof tooltip === "string" ? void 0 : tooltip.shortcut;
5193
- const side = typeof tooltip === "string" ? "top" : tooltip.side ?? "top";
5194
- return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
5195
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: button }),
5196
- /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side, children: [
5197
- tooltipContent,
5198
- shortcut && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 text-muted-foreground", children: shortcut })
5199
- ] })
5200
- ] });
5201
5176
  };
5202
- var PromptInputActionMenu = (props) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu, { ...props });
5203
- var PromptInputActionMenuTrigger = ({
5177
+ var ContextOutputUsage = ({
5204
5178
  className,
5205
5179
  children,
5206
5180
  ...props
5207
- }) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(PromptInputButton, { className, ...props, children: children ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { className: "size-4" }) }) });
5208
- var PromptInputActionMenuContent = ({
5181
+ }) => {
5182
+ const { usage, modelId } = useContextValue();
5183
+ const outputTokens = usage?.outputTokens ?? 0;
5184
+ if (children) {
5185
+ return children;
5186
+ }
5187
+ if (!outputTokens) {
5188
+ return null;
5189
+ }
5190
+ const outputCost = modelId ? tokenlens.getUsage({
5191
+ modelId,
5192
+ usage: { input: 0, output: outputTokens }
5193
+ }).costUSD?.totalUSD : void 0;
5194
+ const outputCostText = new Intl.NumberFormat("en-US", {
5195
+ currency: "USD",
5196
+ style: "currency"
5197
+ }).format(outputCost ?? 0);
5198
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5199
+ "div",
5200
+ {
5201
+ className: cn("flex items-center justify-between text-xs", className),
5202
+ ...props,
5203
+ children: [
5204
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Output" }),
5205
+ /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: outputCostText, tokens: outputTokens })
5206
+ ]
5207
+ }
5208
+ );
5209
+ };
5210
+ var ContextReasoningUsage = ({
5209
5211
  className,
5212
+ children,
5210
5213
  ...props
5211
- }) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "start", className: cn(className), ...props });
5212
- var PromptInputSubmit = ({
5214
+ }) => {
5215
+ const { usage, modelId } = useContextValue();
5216
+ const reasoningTokens = usage?.reasoningTokens ?? 0;
5217
+ if (children) {
5218
+ return children;
5219
+ }
5220
+ if (!reasoningTokens) {
5221
+ return null;
5222
+ }
5223
+ const reasoningCost = modelId ? tokenlens.getUsage({
5224
+ modelId,
5225
+ usage: { reasoningTokens }
5226
+ }).costUSD?.totalUSD : void 0;
5227
+ const reasoningCostText = new Intl.NumberFormat("en-US", {
5228
+ currency: "USD",
5229
+ style: "currency"
5230
+ }).format(reasoningCost ?? 0);
5231
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5232
+ "div",
5233
+ {
5234
+ className: cn("flex items-center justify-between text-xs", className),
5235
+ ...props,
5236
+ children: [
5237
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Reasoning" }),
5238
+ /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: reasoningCostText, tokens: reasoningTokens })
5239
+ ]
5240
+ }
5241
+ );
5242
+ };
5243
+ var ContextCacheUsage = ({
5213
5244
  className,
5214
- variant = "default",
5215
- size = "icon-sm",
5216
- status,
5217
- onStop,
5218
- onClick,
5219
5245
  children,
5220
5246
  ...props
5221
5247
  }) => {
5222
- const isGenerating = status === "submitted" || status === "streaming";
5223
- let Icon = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeftIcon, { className: "size-4" });
5224
- if (status === "submitted") {
5225
- Icon = /* @__PURE__ */ jsxRuntime.jsx(Spinner, {});
5226
- } else if (status === "streaming") {
5227
- Icon = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SquareIcon, { className: "size-4" });
5228
- } else if (status === "error") {
5229
- Icon = /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-4" });
5248
+ const { usage, modelId } = useContextValue();
5249
+ const cacheTokens = usage?.cachedInputTokens ?? 0;
5250
+ if (children) {
5251
+ return children;
5230
5252
  }
5231
- const handleClick = react.useCallback(
5232
- (e) => {
5233
- if (isGenerating && onStop) {
5234
- e.preventDefault();
5235
- onStop();
5236
- return;
5237
- }
5238
- onClick?.(e);
5239
- },
5240
- [isGenerating, onStop, onClick]
5241
- );
5242
- return /* @__PURE__ */ jsxRuntime.jsx(
5243
- InputGroupButton,
5253
+ if (!cacheTokens) {
5254
+ return null;
5255
+ }
5256
+ const cacheCost = modelId ? tokenlens.getUsage({
5257
+ modelId,
5258
+ usage: { cacheReads: cacheTokens, input: 0, output: 0 }
5259
+ }).costUSD?.totalUSD : void 0;
5260
+ const cacheCostText = new Intl.NumberFormat("en-US", {
5261
+ currency: "USD",
5262
+ style: "currency"
5263
+ }).format(cacheCost ?? 0);
5264
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5265
+ "div",
5244
5266
  {
5245
- "aria-label": isGenerating ? "Stop" : "Submit",
5246
- className: cn(className),
5247
- onClick: handleClick,
5248
- size,
5249
- type: isGenerating && onStop ? "button" : "submit",
5250
- variant,
5267
+ className: cn("flex items-center justify-between text-xs", className),
5251
5268
  ...props,
5252
- children: children ?? Icon
5269
+ children: [
5270
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Cache" }),
5271
+ /* @__PURE__ */ jsxRuntime.jsx(TokensWithCost, { costText: cacheCostText, tokens: cacheTokens })
5272
+ ]
5253
5273
  }
5254
5274
  );
5255
5275
  };
@@ -5289,6 +5309,29 @@ function PopoverAnchor({
5289
5309
  function ChatComposer(props) {
5290
5310
  return /* @__PURE__ */ jsxRuntime.jsx(PromptInputProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ChatComposerInner, { ...props }) });
5291
5311
  }
5312
+ function AttachmentPreviewStrip() {
5313
+ const attachments = useProviderAttachments();
5314
+ if (attachments.files.length === 0) return null;
5315
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 px-3 pt-2 pb-1 flex-wrap", children: attachments.files.map((file) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group", children: [
5316
+ file.mediaType?.startsWith("image/") && file.url ? /* @__PURE__ */ jsxRuntime.jsx(
5317
+ "img",
5318
+ {
5319
+ src: file.url,
5320
+ alt: file.filename,
5321
+ className: "h-16 w-16 rounded-lg border border-border object-cover"
5322
+ }
5323
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-16 w-16 rounded-lg border border-border bg-muted flex items-center justify-center text-[10px] text-muted-foreground truncate px-1", children: file.filename }),
5324
+ /* @__PURE__ */ jsxRuntime.jsx(
5325
+ "button",
5326
+ {
5327
+ type: "button",
5328
+ onClick: () => attachments.remove(file.id),
5329
+ className: "absolute -top-1.5 -right-1.5 hidden group-hover:flex items-center justify-center w-4 h-4 rounded-full bg-destructive text-destructive-foreground text-[10px]",
5330
+ children: "\xD7"
5331
+ }
5332
+ )
5333
+ ] }, file.id)) });
5334
+ }
5292
5335
  function ChatComposerInner({
5293
5336
  onSend,
5294
5337
  onStop,
@@ -5381,7 +5424,13 @@ function ChatComposerInner({
5381
5424
  (message) => {
5382
5425
  const text = message.text.trim();
5383
5426
  if (!text || isRunning || disabled) return;
5384
- onSend(text);
5427
+ const images = [];
5428
+ for (const file of message.files) {
5429
+ if (file.mediaType?.startsWith("image/") && file.url) {
5430
+ images.push({ data: file.url, mimeType: file.mediaType });
5431
+ }
5432
+ }
5433
+ onSend(text, images.length > 0 ? images : void 0);
5385
5434
  },
5386
5435
  [onSend, isRunning, disabled]
5387
5436
  );
@@ -5390,7 +5439,8 @@ function ChatComposerInner({
5390
5439
  setButtonMenuOpen(false);
5391
5440
  }
5392
5441
  }, children: [
5393
- /* @__PURE__ */ jsxRuntime.jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(PromptInput, { onSubmit: handleSubmit, children: [
5442
+ /* @__PURE__ */ jsxRuntime.jsx(AttachmentPreviewStrip, {}),
5443
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(PromptInput, { onSubmit: handleSubmit, accept: "image/*", multiple: true, children: [
5394
5444
  /* @__PURE__ */ jsxRuntime.jsx(PromptInputBody, { children: /* @__PURE__ */ jsxRuntime.jsx(
5395
5445
  PromptInputTextarea,
5396
5446
  {
@@ -8290,23 +8340,27 @@ function useAgentChatRuntime({
8290
8340
  closeStream();
8291
8341
  };
8292
8342
  }, [adapter, clearReconnectTimer, closeStream, sessionId]);
8293
- const markSending = react.useCallback((content) => {
8294
- setState((prev) => ({
8295
- ...prev,
8296
- terminal: false,
8297
- isRunning: true,
8298
- messages: [
8299
- ...prev.messages,
8300
- {
8301
- id: `local-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
8302
- role: "user",
8303
- content,
8304
- createdAt: /* @__PURE__ */ new Date(),
8305
- status: "complete"
8306
- }
8307
- ]
8308
- }));
8309
- }, []);
8343
+ const markSending = react.useCallback(
8344
+ (content, images) => {
8345
+ setState((prev) => ({
8346
+ ...prev,
8347
+ terminal: false,
8348
+ isRunning: true,
8349
+ messages: [
8350
+ ...prev.messages,
8351
+ {
8352
+ id: `local-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
8353
+ role: "user",
8354
+ content,
8355
+ createdAt: /* @__PURE__ */ new Date(),
8356
+ status: "complete",
8357
+ images: images?.length ? images : void 0
8358
+ }
8359
+ ]
8360
+ }));
8361
+ },
8362
+ []
8363
+ );
8310
8364
  const markSendError = react.useCallback((errorText) => {
8311
8365
  setState((prev) => {
8312
8366
  for (let i = prev.messages.length - 1; i >= 0; i--) {
@@ -8357,13 +8411,13 @@ function useAgentChatRuntime({
8357
8411
  });
8358
8412
  }, []);
8359
8413
  const send = react.useCallback(
8360
- async (content) => {
8361
- markSending(content);
8414
+ async (content, images) => {
8415
+ markSending(content, images);
8362
8416
  if (!sessionId) {
8363
8417
  try {
8364
8418
  const session = await adapter.createSession({ agentId });
8365
8419
  onSessionChange?.(session.id);
8366
- await adapter.sendMessage({ sessionId: session.id, content });
8420
+ await adapter.sendMessage({ sessionId: session.id, content, images });
8367
8421
  } catch (error) {
8368
8422
  markSendError(error instanceof Error ? error.message : "send failed");
8369
8423
  throw error;
@@ -8371,7 +8425,7 @@ function useAgentChatRuntime({
8371
8425
  return;
8372
8426
  }
8373
8427
  try {
8374
- await adapter.sendMessage({ sessionId, content });
8428
+ await adapter.sendMessage({ sessionId, content, images });
8375
8429
  } catch (error) {
8376
8430
  markSendError(error instanceof Error ? error.message : "send failed");
8377
8431
  throw error;
@@ -8477,7 +8531,7 @@ function AgentChat({
8477
8531
  messages: runtime.messages,
8478
8532
  isRunning: runtime.isRunning,
8479
8533
  isLoadingHistory: runtime.isLoadingHistory,
8480
- onSend: (content) => void runtime.send(content),
8534
+ onSend: (content, images) => void runtime.send(content, images),
8481
8535
  onStop: () => void runtime.stop(),
8482
8536
  onRetry: runtime.retry,
8483
8537
  onFileSelect: handleFileSelect,