@codori/client 0.0.6 → 0.0.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.
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
removePendingUserMessageId,
|
|
9
9
|
resolvePromptSubmitStatus,
|
|
10
10
|
resolveTurnSubmissionMethod,
|
|
11
|
+
shouldApplyNotificationToCurrentTurn,
|
|
11
12
|
shouldSubmitViaTurnSteer,
|
|
12
13
|
shouldAwaitThreadHydration,
|
|
13
14
|
shouldRetrySteerWithTurnStart,
|
|
@@ -135,6 +136,7 @@ const composerError = computed(() => attachmentError.value ?? error.value)
|
|
|
135
136
|
const submitError = computed(() => composerError.value ? new Error(composerError.value) : undefined)
|
|
136
137
|
const interruptRequested = ref(false)
|
|
137
138
|
const awaitingAssistantOutput = ref(false)
|
|
139
|
+
const sendMessageLocked = ref(false)
|
|
138
140
|
const isBusy = computed(() =>
|
|
139
141
|
status.value === 'submitted'
|
|
140
142
|
|| status.value === 'streaming'
|
|
@@ -467,7 +469,11 @@ const ensurePendingLiveStream = async () => {
|
|
|
467
469
|
}
|
|
468
470
|
|
|
469
471
|
const turnId = notificationTurnId(notification)
|
|
470
|
-
if (
|
|
472
|
+
if (!shouldApplyNotificationToCurrentTurn({
|
|
473
|
+
liveStreamTurnId: liveStream.turnId,
|
|
474
|
+
notificationMethod: notification.method,
|
|
475
|
+
notificationTurnId: turnId
|
|
476
|
+
})) {
|
|
471
477
|
return
|
|
472
478
|
}
|
|
473
479
|
|
|
@@ -806,7 +812,11 @@ const hydrateThread = async (threadId: string) => {
|
|
|
806
812
|
}
|
|
807
813
|
|
|
808
814
|
const turnId = notificationTurnId(notification)
|
|
809
|
-
if (
|
|
815
|
+
if (!shouldApplyNotificationToCurrentTurn({
|
|
816
|
+
liveStreamTurnId: nextLiveStream.turnId,
|
|
817
|
+
notificationMethod: notification.method,
|
|
818
|
+
notificationTurnId: turnId
|
|
819
|
+
})) {
|
|
810
820
|
return
|
|
811
821
|
}
|
|
812
822
|
|
|
@@ -1764,118 +1774,131 @@ const applyNotification = (notification: CodexRpcNotification) => {
|
|
|
1764
1774
|
}
|
|
1765
1775
|
|
|
1766
1776
|
const sendMessage = async () => {
|
|
1777
|
+
if (sendMessageLocked.value) {
|
|
1778
|
+
return
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
sendMessageLocked.value = true
|
|
1767
1782
|
const text = input.value.trim()
|
|
1768
1783
|
const submittedAttachments = attachments.value.slice()
|
|
1769
1784
|
|
|
1770
1785
|
if (!text && submittedAttachments.length === 0) {
|
|
1786
|
+
sendMessageLocked.value = false
|
|
1771
1787
|
return
|
|
1772
1788
|
}
|
|
1773
1789
|
|
|
1790
|
+
input.value = ''
|
|
1791
|
+
clearAttachments({ revoke: false })
|
|
1792
|
+
|
|
1774
1793
|
try {
|
|
1775
1794
|
await loadPromptControls()
|
|
1776
1795
|
} catch (caughtError) {
|
|
1796
|
+
restoreDraftIfPristine(text, submittedAttachments)
|
|
1777
1797
|
error.value = caughtError instanceof Error ? caughtError.message : String(caughtError)
|
|
1778
1798
|
status.value = 'error'
|
|
1799
|
+
sendMessageLocked.value = false
|
|
1779
1800
|
return
|
|
1780
1801
|
}
|
|
1781
1802
|
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1803
|
+
try {
|
|
1804
|
+
if (pendingThreadHydration && shouldAwaitThreadHydration({
|
|
1805
|
+
hasPendingThreadHydration: true,
|
|
1806
|
+
routeThreadId: routeThreadId.value
|
|
1807
|
+
})) {
|
|
1808
|
+
await pendingThreadHydration
|
|
1809
|
+
}
|
|
1788
1810
|
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
let startedLiveStream: LiveStream | null = null
|
|
1804
|
-
let executedSubmissionMethod = submissionMethod
|
|
1811
|
+
pinnedToBottom.value = true
|
|
1812
|
+
error.value = null
|
|
1813
|
+
attachmentError.value = null
|
|
1814
|
+
const submissionMethod = resolveTurnSubmissionMethod(shouldSubmitWithTurnSteer())
|
|
1815
|
+
if (submissionMethod === 'turn/start') {
|
|
1816
|
+
status.value = 'submitted'
|
|
1817
|
+
}
|
|
1818
|
+
const optimisticMessage = buildOptimisticMessage(text, submittedAttachments)
|
|
1819
|
+
const optimisticMessageId = optimisticMessage.id
|
|
1820
|
+
rememberOptimisticAttachments(optimisticMessageId, submittedAttachments)
|
|
1821
|
+
messages.value = [...messages.value, optimisticMessage]
|
|
1822
|
+
markAwaitingAssistantOutput(shouldAwaitAssistantOutput(submissionMethod))
|
|
1823
|
+
let startedLiveStream: LiveStream | null = null
|
|
1824
|
+
let executedSubmissionMethod = submissionMethod
|
|
1805
1825
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1826
|
+
try {
|
|
1827
|
+
const client = getClient(props.projectId)
|
|
1808
1828
|
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
try {
|
|
1815
|
-
uploadedAttachments = await uploadAttachments(liveStream.threadId, submittedAttachments)
|
|
1816
|
-
const turnId = await waitForLiveStreamTurnId(liveStream)
|
|
1817
|
-
|
|
1818
|
-
await client.request<TurnStartResponse>('turn/steer', {
|
|
1819
|
-
threadId: liveStream.threadId,
|
|
1820
|
-
expectedTurnId: turnId,
|
|
1821
|
-
input: buildTurnStartInput(text, uploadedAttachments),
|
|
1822
|
-
...buildTurnOverrides(selectedModel.value, selectedEffort.value)
|
|
1823
|
-
})
|
|
1824
|
-
tokenUsage.value = null
|
|
1825
|
-
} catch (caughtError) {
|
|
1826
|
-
const errorToHandle = caughtError instanceof Error ? caughtError : new Error(String(caughtError))
|
|
1827
|
-
if (!shouldRetrySteerWithTurnStart(errorToHandle.message)) {
|
|
1828
|
-
throw errorToHandle
|
|
1829
|
-
}
|
|
1829
|
+
if (submissionMethod === 'turn/steer') {
|
|
1830
|
+
const liveStream = await ensurePendingLiveStream()
|
|
1831
|
+
queuePendingUserMessage(liveStream, optimisticMessageId)
|
|
1832
|
+
let uploadedAttachments: PersistedProjectAttachment[] | undefined
|
|
1830
1833
|
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
setLiveStreamTurnId(liveStream, null)
|
|
1835
|
-
setLiveStreamInterruptRequested(liveStream, false)
|
|
1834
|
+
try {
|
|
1835
|
+
uploadedAttachments = await uploadAttachments(liveStream.threadId, submittedAttachments)
|
|
1836
|
+
const turnId = await waitForLiveStreamTurnId(liveStream)
|
|
1836
1837
|
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1838
|
+
await client.request<TurnStartResponse>('turn/steer', {
|
|
1839
|
+
threadId: liveStream.threadId,
|
|
1840
|
+
expectedTurnId: turnId,
|
|
1841
|
+
input: buildTurnStartInput(text, uploadedAttachments),
|
|
1842
|
+
...buildTurnOverrides(selectedModel.value, selectedEffort.value)
|
|
1843
|
+
})
|
|
1844
|
+
tokenUsage.value = null
|
|
1845
|
+
} catch (caughtError) {
|
|
1846
|
+
const errorToHandle = caughtError instanceof Error ? caughtError : new Error(String(caughtError))
|
|
1847
|
+
if (!shouldRetrySteerWithTurnStart(errorToHandle.message)) {
|
|
1848
|
+
throw errorToHandle
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
executedSubmissionMethod = 'turn/start'
|
|
1852
|
+
startedLiveStream = liveStream
|
|
1853
|
+
status.value = 'submitted'
|
|
1854
|
+
setLiveStreamTurnId(liveStream, null)
|
|
1855
|
+
setLiveStreamInterruptRequested(liveStream, false)
|
|
1856
|
+
|
|
1857
|
+
await submitTurnStart({
|
|
1858
|
+
client,
|
|
1859
|
+
liveStream,
|
|
1860
|
+
text,
|
|
1861
|
+
submittedAttachments,
|
|
1862
|
+
uploadedAttachments,
|
|
1863
|
+
optimisticMessageId,
|
|
1864
|
+
queueOptimisticMessage: false
|
|
1865
|
+
})
|
|
1866
|
+
}
|
|
1867
|
+
return
|
|
1846
1868
|
}
|
|
1847
|
-
return
|
|
1848
|
-
}
|
|
1849
1869
|
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1870
|
+
const liveStream = await ensurePendingLiveStream()
|
|
1871
|
+
startedLiveStream = liveStream
|
|
1872
|
+
await submitTurnStart({
|
|
1873
|
+
client,
|
|
1874
|
+
liveStream,
|
|
1875
|
+
text,
|
|
1876
|
+
submittedAttachments,
|
|
1877
|
+
optimisticMessageId
|
|
1878
|
+
})
|
|
1879
|
+
} catch (caughtError) {
|
|
1880
|
+
const messageText = caughtError instanceof Error ? caughtError.message : String(caughtError)
|
|
1861
1881
|
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1882
|
+
markAwaitingAssistantOutput(false)
|
|
1883
|
+
untrackPendingUserMessage(optimisticMessageId)
|
|
1884
|
+
removeOptimisticMessage(optimisticMessageId)
|
|
1865
1885
|
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1886
|
+
if (executedSubmissionMethod === 'turn/start') {
|
|
1887
|
+
if (startedLiveStream && session.liveStream === startedLiveStream) {
|
|
1888
|
+
clearPendingOptimisticMessages(clearLiveStream(new Error(messageText)))
|
|
1889
|
+
}
|
|
1890
|
+
session.pendingLiveStream = null
|
|
1891
|
+
restoreDraftIfPristine(text, submittedAttachments)
|
|
1892
|
+
error.value = messageText
|
|
1893
|
+
status.value = 'error'
|
|
1894
|
+
return
|
|
1869
1895
|
}
|
|
1870
|
-
|
|
1896
|
+
|
|
1871
1897
|
restoreDraftIfPristine(text, submittedAttachments)
|
|
1872
1898
|
error.value = messageText
|
|
1873
|
-
status.value = 'error'
|
|
1874
|
-
return
|
|
1875
1899
|
}
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
error.value = messageText
|
|
1900
|
+
} finally {
|
|
1901
|
+
sendMessageLocked.value = false
|
|
1879
1902
|
}
|
|
1880
1903
|
}
|
|
1881
1904
|
|
|
@@ -2077,19 +2100,11 @@ watch([selectedModel, availableModels], () => {
|
|
|
2077
2100
|
/>
|
|
2078
2101
|
</template>
|
|
2079
2102
|
<template #indicator>
|
|
2080
|
-
<
|
|
2103
|
+
<UChatShimmer
|
|
2081
2104
|
v-if="awaitingAssistantOutput"
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
name="i-lucide-loader-circle"
|
|
2086
|
-
class="size-4 animate-spin text-primary"
|
|
2087
|
-
/>
|
|
2088
|
-
<div class="flex flex-col gap-1">
|
|
2089
|
-
<UChatShimmer text="Waiting for response…" />
|
|
2090
|
-
<span class="text-xs text-toned">Real reasoning will appear separately when streaming starts.</span>
|
|
2091
|
-
</div>
|
|
2092
|
-
</div>
|
|
2105
|
+
text="Thinking..."
|
|
2106
|
+
class="px-1 py-2"
|
|
2107
|
+
/>
|
|
2093
2108
|
</template>
|
|
2094
2109
|
</UChatMessages>
|
|
2095
2110
|
</div>
|
|
@@ -31,9 +31,10 @@ export const shouldSubmitViaTurnSteer = (input: {
|
|
|
31
31
|
liveStreamTurnId: string | null
|
|
32
32
|
status: PromptSubmitStatus
|
|
33
33
|
}) =>
|
|
34
|
-
input.activeThreadId !== null
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
(input.activeThreadId !== null
|
|
35
|
+
&& input.liveStreamThreadId === input.activeThreadId
|
|
36
|
+
&& input.status === 'submitted')
|
|
37
|
+
|| hasSteerableTurn(input)
|
|
37
38
|
|
|
38
39
|
export const shouldAwaitThreadHydration = (input: {
|
|
39
40
|
hasPendingThreadHydration: boolean
|
|
@@ -43,7 +44,17 @@ export const shouldAwaitThreadHydration = (input: {
|
|
|
43
44
|
&& input.routeThreadId !== null
|
|
44
45
|
|
|
45
46
|
export const shouldRetrySteerWithTurnStart = (message: string) =>
|
|
46
|
-
/no active turn to steer/i.test(message)
|
|
47
|
+
/no active turn to steer|active turn is no longer available/i.test(message)
|
|
48
|
+
|
|
49
|
+
export const shouldApplyNotificationToCurrentTurn = (input: {
|
|
50
|
+
liveStreamTurnId: string | null
|
|
51
|
+
notificationMethod: string
|
|
52
|
+
notificationTurnId: string | null
|
|
53
|
+
}) =>
|
|
54
|
+
input.liveStreamTurnId === null
|
|
55
|
+
|| input.notificationTurnId === null
|
|
56
|
+
|| input.notificationTurnId === input.liveStreamTurnId
|
|
57
|
+
|| input.notificationMethod === 'turn/started'
|
|
47
58
|
|
|
48
59
|
export const resolvePromptSubmitStatus = (input: {
|
|
49
60
|
status: PromptSubmitStatus
|