Skip to content

Commit 3f5fbbc

Browse files
authored
fix: add shared ExtendedToolState for approval states (#104)
- Create shared types.ts for ExtendedToolState definition - Fix TypeScript errors in ToolStatusBadge and Confirmation components - Add type safety for 'approval-requested', 'approval-responded', 'output-denied' states - Improve accessibility with aria-label and ARIA attributes - Replace 'any' types with proper SpeechRecognition types
1 parent 6d5a3b6 commit 3f5fbbc

File tree

12 files changed

+37
-13
lines changed

12 files changed

+37
-13
lines changed

packages/elements/src/confirmation/Confirmation.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
2-
import type { ToolUIPart } from 'ai'
32
import type { HTMLAttributes } from 'vue'
3+
import type { ExtendedToolState } from '../types'
44
import type { ToolUIPartApproval } from './context'
55
import { Alert } from '@repo/shadcn-vue/components/ui/alert'
66
import { cn } from '@repo/shadcn-vue/lib/utils'
@@ -9,7 +9,7 @@ import { ConfirmationKey } from './context'
99
1010
const props = defineProps<{
1111
approval?: ToolUIPartApproval
12-
state: ToolUIPart['state']
12+
state: ExtendedToolState
1313
class?: HTMLAttributes['class']
1414
}>()
1515

packages/elements/src/confirmation/context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { ToolUIPart } from 'ai'
21
import type { InjectionKey, Ref } from 'vue'
2+
import type { ExtendedToolState } from '../types'
33
import { inject } from 'vue'
44

55
export type ToolUIPartApproval
@@ -32,7 +32,7 @@ export type ToolUIPartApproval
3232

3333
export interface ConfirmationContextValue {
3434
approval: Ref<ToolUIPartApproval>
35-
state: Ref<ToolUIPart['state']>
35+
state: Ref<ExtendedToolState>
3636
}
3737

3838
export const ConfirmationKey: InjectionKey<ConfirmationContextValue>

packages/elements/src/conversation/ConversationScrollButton.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function handleClick() {
2323
<Button
2424
v-if="showScrollButton"
2525
:class="cn('absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full', props.class)"
26+
aria-label="Scroll to bottom"
2627
size="icon"
2728
type="button"
2829
variant="outline"

packages/elements/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ export * from './sources'
2020
export * from './suggestion'
2121
export * from './task'
2222
export * from './tool'
23+
export type { ExtendedToolState } from './types'
2324
export * from './web-preview'

packages/elements/src/loader/Loader.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ const props = withDefaults(defineProps<Props>(), {
1616
<template>
1717
<div
1818
:class="cn('inline-flex animate-spin items-center justify-center', props.class)"
19+
aria-label="Loading"
20+
aria-live="polite"
21+
role="status"
1922
v-bind="$attrs"
2023
>
2124
<LoaderIcon :size="props.size" />

packages/elements/src/prompt-input/PromptInputSpeechButton.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ onMounted(() => {
8181
sr.onstart = () => isListening.value = true
8282
sr.onend = () => isListening.value = false
8383
84-
sr.onresult = (event: any) => {
84+
sr.onresult = (event: SpeechRecognitionEvent) => {
8585
let finalTranscript = ''
8686
for (let i = event.resultIndex; i < event.results.length; i++) {
8787
const result = event.results[i]
@@ -96,7 +96,7 @@ onMounted(() => {
9696
}
9797
}
9898
99-
sr.onerror = (event: any) => {
99+
sr.onerror = (event: SpeechRecognitionErrorEvent) => {
100100
console.error('Speech recognition error:', event.error)
101101
isListening.value = false
102102
}

packages/elements/src/tool/ToolStatusBadge.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!-- StatusBadge.vue -->
22
<script setup lang="ts">
3-
import type { ToolUIPart } from 'ai'
43
import type { Component } from 'vue'
4+
import type { ExtendedToolState } from '../types'
55
import { Badge } from '@repo/shadcn-vue/components/ui/badge'
66
import {
77
CheckCircleIcon,
@@ -12,11 +12,11 @@ import {
1212
import { computed } from 'vue'
1313
1414
const props = defineProps<{
15-
state: ToolUIPart['state']
15+
state: ExtendedToolState
1616
}>()
1717
1818
const label = computed(() => {
19-
const labels: Record<ToolUIPart['state'], string> = {
19+
const labels: Record<ExtendedToolState, string> = {
2020
'input-streaming': 'Pending',
2121
'input-available': 'Running',
2222
'approval-requested': 'Awaiting Approval',
@@ -29,7 +29,7 @@ const label = computed(() => {
2929
})
3030
3131
const icon = computed<Component>(() => {
32-
const icons: Record<ToolUIPart['state'], Component> = {
32+
const icons: Record<ExtendedToolState, Component> = {
3333
'input-streaming': CircleIcon,
3434
'input-available': ClockIcon,
3535
'approval-requested': ClockIcon,

packages/elements/src/tool/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export type { ExtendedToolState } from '../types'
12
export { default as Tool } from './Tool.vue'
23
export { default as ToolContent } from './ToolContent.vue'
34
export { default as ToolHeader } from './ToolHeader.vue'

packages/elements/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { ToolUIPart } from 'ai'
2+
3+
/**
4+
* Extended tool state type that includes approval-related states
5+
* beyond what the base AI SDK provides.
6+
*
7+
* This type is used across multiple components including:
8+
* - Tool components (ToolStatusBadge)
9+
* - Confirmation components
10+
*/
11+
export type ExtendedToolState
12+
= | ToolUIPart['state']
13+
| 'approval-requested'
14+
| 'approval-responded'
15+
| 'output-denied'

packages/examples/src/confirmation-accepted.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import type { ExtendedToolState } from '@repo/elements/tool'
23
import {
34
Confirmation,
45
ConfirmationAccepted,
@@ -15,7 +16,7 @@ const approval = {
1516
approved: true,
1617
}
1718
18-
const state = 'approval-responded'
19+
const state: ExtendedToolState = 'approval-responded'
1920
</script>
2021

2122
<template>

0 commit comments

Comments
 (0)