|
@@ -89,54 +89,55 @@
|
|
|
</script>
|
|
|
|
|
|
<div {id} class={className}>
|
|
|
- {#if title !== null}
|
|
|
- <!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
|
- <!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
|
- <div
|
|
|
- class="{buttonClassName} cursor-pointer"
|
|
|
- on:pointerup={() => {
|
|
|
- if (!disabled) {
|
|
|
- open = !open;
|
|
|
- }
|
|
|
- }}
|
|
|
- >
|
|
|
+ {#if attributes?.type === 'tool_calls'}
|
|
|
+ {@const args = decode(attributes?.arguments)}
|
|
|
+ {@const result = decode(attributes?.result ?? '')}
|
|
|
+ {@const files = parseJSONString(decode(attributes?.files ?? ''))}
|
|
|
+ {@const embeds = parseJSONString(decode(attributes?.embeds ?? ''))}
|
|
|
+
|
|
|
+ {#if embeds && Array.isArray(embeds) && embeds.length > 0}
|
|
|
+ <div class="py-1 w-full cursor-pointer">
|
|
|
+ <div class=" w-full text-xs text-gray-500">
|
|
|
+ <div class="">
|
|
|
+ {attributes.name}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {#each embeds as embed, idx}
|
|
|
+ <div class="my-2" id={`${collapsibleId}-tool-calls-${attributes?.id}-embed-${idx}`}>
|
|
|
+ <FullHeightIframe
|
|
|
+ src={embed}
|
|
|
+ allowScripts={true}
|
|
|
+ allowForms={true}
|
|
|
+ allowSameOrigin={true}
|
|
|
+ allowPopups={true}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ {/each}
|
|
|
+ </div>
|
|
|
+ {:else}
|
|
|
<div
|
|
|
- class=" w-full font-medium flex items-center justify-between gap-2 {attributes?.done &&
|
|
|
- attributes?.done !== 'true'
|
|
|
- ? 'shimmer'
|
|
|
- : ''}
|
|
|
- "
|
|
|
+ class="{buttonClassName} cursor-pointer"
|
|
|
+ on:pointerup={() => {
|
|
|
+ if (!disabled) {
|
|
|
+ open = !open;
|
|
|
+ }
|
|
|
+ }}
|
|
|
>
|
|
|
- {#if attributes?.done && attributes?.done !== 'true'}
|
|
|
- <div>
|
|
|
- <Spinner className="size-4" />
|
|
|
- </div>
|
|
|
- {/if}
|
|
|
+ <div
|
|
|
+ class=" w-full font-medium flex items-center justify-between gap-2 {attributes?.done &&
|
|
|
+ attributes?.done !== 'true'
|
|
|
+ ? 'shimmer'
|
|
|
+ : ''}
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {#if attributes?.done && attributes?.done !== 'true'}
|
|
|
+ <div>
|
|
|
+ <Spinner className="size-4" />
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
|
|
|
- <div class="">
|
|
|
- {#if attributes?.type === 'reasoning'}
|
|
|
- {#if attributes?.done === 'true' && attributes?.duration}
|
|
|
- {#if attributes.duration < 1}
|
|
|
- {$i18n.t('Thought for less than a second')}
|
|
|
- {:else if attributes.duration < 60}
|
|
|
- {$i18n.t('Thought for {{DURATION}} seconds', {
|
|
|
- DURATION: attributes.duration
|
|
|
- })}
|
|
|
- {:else}
|
|
|
- {$i18n.t('Thought for {{DURATION}}', {
|
|
|
- DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
|
|
|
- })}
|
|
|
- {/if}
|
|
|
- {:else}
|
|
|
- {$i18n.t('Thinking...')}
|
|
|
- {/if}
|
|
|
- {:else if attributes?.type === 'code_interpreter'}
|
|
|
- {#if attributes?.done === 'true'}
|
|
|
- {$i18n.t('Analyzed')}
|
|
|
- {:else}
|
|
|
- {$i18n.t('Analyzing...')}
|
|
|
- {/if}
|
|
|
- {:else if attributes?.type === 'tool_calls'}
|
|
|
+ <div class="">
|
|
|
{#if attributes?.done === 'true'}
|
|
|
<Markdown
|
|
|
id={`${collapsibleId}-tool-calls-${attributes?.id}`}
|
|
@@ -152,130 +153,172 @@
|
|
|
})}
|
|
|
/>
|
|
|
{/if}
|
|
|
- {:else}
|
|
|
- {title}
|
|
|
- {/if}
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <div class="flex self-center translate-y-[1px]">
|
|
|
- {#if open}
|
|
|
- <ChevronUp strokeWidth="3.5" className="size-3.5" />
|
|
|
- {:else}
|
|
|
- <ChevronDown strokeWidth="3.5" className="size-3.5" />
|
|
|
- {/if}
|
|
|
+ <div class="flex self-center translate-y-[1px]">
|
|
|
+ {#if open}
|
|
|
+ <ChevronUp strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {:else}
|
|
|
+ <ChevronDown strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- {:else}
|
|
|
- <!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
|
- <!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
|
- <div
|
|
|
- class="{buttonClassName} cursor-pointer"
|
|
|
- on:click={(e) => {
|
|
|
- e.stopPropagation();
|
|
|
- }}
|
|
|
- on:pointerup={(e) => {
|
|
|
- if (!disabled) {
|
|
|
- open = !open;
|
|
|
- }
|
|
|
- }}
|
|
|
- >
|
|
|
- <div>
|
|
|
- <div class="flex items-start justify-between">
|
|
|
- <slot />
|
|
|
|
|
|
- {#if chevron}
|
|
|
- <div class="flex self-start translate-y-1">
|
|
|
- {#if open}
|
|
|
- <ChevronUp strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {#if !grow}
|
|
|
+ {#if open && !hide}
|
|
|
+ <div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
|
|
|
+ {#if attributes?.type === 'tool_calls'}
|
|
|
+ {#if attributes?.done === 'true'}
|
|
|
+ <Markdown
|
|
|
+ id={`${collapsibleId}-tool-calls-${attributes?.id}-result`}
|
|
|
+ content={`> \`\`\`json
|
|
|
+> ${formatJSONString(args)}
|
|
|
+> ${formatJSONString(result)}
|
|
|
+> \`\`\``}
|
|
|
+ />
|
|
|
{:else}
|
|
|
- <ChevronDown strokeWidth="3.5" className="size-3.5" />
|
|
|
+ <Markdown
|
|
|
+ id={`${collapsibleId}-tool-calls-${attributes?.id}-result`}
|
|
|
+ content={`> \`\`\`json
|
|
|
+> ${formatJSONString(args)}
|
|
|
+> \`\`\``}
|
|
|
+ />
|
|
|
{/if}
|
|
|
- </div>
|
|
|
- {/if}
|
|
|
- </div>
|
|
|
-
|
|
|
- {#if grow}
|
|
|
- {#if open && !hide}
|
|
|
- <div
|
|
|
- transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}
|
|
|
- on:pointerup={(e) => {
|
|
|
- e.stopPropagation();
|
|
|
- }}
|
|
|
- >
|
|
|
+ {:else}
|
|
|
<slot name="content" />
|
|
|
- </div>
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
+
|
|
|
+ {#if attributes?.done === 'true'}
|
|
|
+ {#if typeof files === 'object'}
|
|
|
+ {#each files ?? [] as file, idx}
|
|
|
+ {#if file.startsWith('data:image/')}
|
|
|
+ <Image
|
|
|
+ id={`${collapsibleId}-tool-calls-${attributes?.id}-result-${idx}`}
|
|
|
+ src={file}
|
|
|
+ alt="Image"
|
|
|
+ />
|
|
|
+ {/if}
|
|
|
+ {/each}
|
|
|
{/if}
|
|
|
{/if}
|
|
|
+ {/if}
|
|
|
+ {/if}
|
|
|
+ {:else}
|
|
|
+ {#if title !== null}
|
|
|
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
|
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
|
+ <div
|
|
|
+ class="{buttonClassName} cursor-pointer"
|
|
|
+ on:pointerup={() => {
|
|
|
+ if (!disabled) {
|
|
|
+ open = !open;
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class=" w-full font-medium flex items-center justify-between gap-2 {attributes?.done &&
|
|
|
+ attributes?.done !== 'true'
|
|
|
+ ? 'shimmer'
|
|
|
+ : ''}
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {#if attributes?.done && attributes?.done !== 'true'}
|
|
|
+ <div>
|
|
|
+ <Spinner className="size-4" />
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
+
|
|
|
+ <div class="">
|
|
|
+ {#if attributes?.type === 'reasoning'}
|
|
|
+ {#if attributes?.done === 'true' && attributes?.duration}
|
|
|
+ {#if attributes.duration < 1}
|
|
|
+ {$i18n.t('Thought for less than a second')}
|
|
|
+ {:else if attributes.duration < 60}
|
|
|
+ {$i18n.t('Thought for {{DURATION}} seconds', {
|
|
|
+ DURATION: attributes.duration
|
|
|
+ })}
|
|
|
+ {:else}
|
|
|
+ {$i18n.t('Thought for {{DURATION}}', {
|
|
|
+ DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
|
|
|
+ })}
|
|
|
+ {/if}
|
|
|
+ {:else}
|
|
|
+ {$i18n.t('Thinking...')}
|
|
|
+ {/if}
|
|
|
+ {:else if attributes?.type === 'code_interpreter'}
|
|
|
+ {#if attributes?.done === 'true'}
|
|
|
+ {$i18n.t('Analyzed')}
|
|
|
+ {:else}
|
|
|
+ {$i18n.t('Analyzing...')}
|
|
|
+ {/if}
|
|
|
+ {:else}
|
|
|
+ {title}
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="flex self-center translate-y-[1px]">
|
|
|
+ {#if open}
|
|
|
+ <ChevronUp strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {:else}
|
|
|
+ <ChevronDown strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- {/if}
|
|
|
+ {:else}
|
|
|
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
|
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
|
+ <div
|
|
|
+ class="{buttonClassName} cursor-pointer"
|
|
|
+ on:click={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ }}
|
|
|
+ on:pointerup={(e) => {
|
|
|
+ if (!disabled) {
|
|
|
+ open = !open;
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <div class="flex items-start justify-between">
|
|
|
+ <slot />
|
|
|
|
|
|
- {#if attributes?.type === 'tool_calls'}
|
|
|
- {@const args = decode(attributes?.arguments)}
|
|
|
- {@const result = decode(attributes?.result ?? '')}
|
|
|
- {@const files = parseJSONString(decode(attributes?.files ?? ''))}
|
|
|
- {@const embeds = parseJSONString(decode(attributes?.embeds ?? ''))}
|
|
|
+ {#if chevron}
|
|
|
+ <div class="flex self-start translate-y-1">
|
|
|
+ {#if open}
|
|
|
+ <ChevronUp strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {:else}
|
|
|
+ <ChevronDown strokeWidth="3.5" className="size-3.5" />
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
+ </div>
|
|
|
|
|
|
- {#if embeds && Array.isArray(embeds) && embeds.length > 0}
|
|
|
- {#each embeds as embed, idx}
|
|
|
- <div class="my-2" id={`${collapsibleId}-tool-calls-${attributes?.id}-embed-${idx}`}>
|
|
|
- <FullHeightIframe
|
|
|
- src={embed}
|
|
|
- allowScripts={true}
|
|
|
- allowForms={$settings?.iframeSandboxAllowForms ?? false}
|
|
|
- allowSameOrigin={$settings?.iframeSandboxAllowSameOrigin ?? false}
|
|
|
- allowPopups={$settings?.iframeSandboxAllowPopups ?? false}
|
|
|
- />
|
|
|
+ {#if grow}
|
|
|
+ {#if open && !hide}
|
|
|
+ <div
|
|
|
+ transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}
|
|
|
+ on:pointerup={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <slot name="content" />
|
|
|
+ </div>
|
|
|
+ {/if}
|
|
|
+ {/if}
|
|
|
</div>
|
|
|
- {/each}
|
|
|
+ </div>
|
|
|
{/if}
|
|
|
|
|
|
{#if !grow}
|
|
|
{#if open && !hide}
|
|
|
<div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
|
|
|
- {#if attributes?.type === 'tool_calls'}
|
|
|
- {#if attributes?.done === 'true'}
|
|
|
- <Markdown
|
|
|
- id={`${collapsibleId}-tool-calls-${attributes?.id}-result`}
|
|
|
- content={`> \`\`\`json
|
|
|
-> ${formatJSONString(args)}
|
|
|
-> ${formatJSONString(result)}
|
|
|
-> \`\`\``}
|
|
|
- />
|
|
|
- {:else}
|
|
|
- <Markdown
|
|
|
- id={`${collapsibleId}-tool-calls-${attributes?.id}-result`}
|
|
|
- content={`> \`\`\`json
|
|
|
-> ${formatJSONString(args)}
|
|
|
-> \`\`\``}
|
|
|
- />
|
|
|
- {/if}
|
|
|
- {:else}
|
|
|
- <slot name="content" />
|
|
|
- {/if}
|
|
|
+ <slot name="content" />
|
|
|
</div>
|
|
|
{/if}
|
|
|
-
|
|
|
- {#if attributes?.done === 'true'}
|
|
|
- {#if typeof files === 'object'}
|
|
|
- {#each files ?? [] as file, idx}
|
|
|
- {#if file.startsWith('data:image/')}
|
|
|
- <Image
|
|
|
- id={`${collapsibleId}-tool-calls-${attributes?.id}-result-${idx}`}
|
|
|
- src={file}
|
|
|
- alt="Image"
|
|
|
- />
|
|
|
- {/if}
|
|
|
- {/each}
|
|
|
- {/if}
|
|
|
- {/if}
|
|
|
- {/if}
|
|
|
- {:else if !grow}
|
|
|
- {#if open && !hide}
|
|
|
- <div transition:slide={{ duration: 300, easing: quintOut, axis: 'y' }}>
|
|
|
- <slot name="content" />
|
|
|
- </div>
|
|
|
{/if}
|
|
|
{/if}
|
|
|
</div>
|