experimental-a2 0.15.0 → 0.16.1
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/CHANGELOG.md +81 -0
- package/dist/actor-client.d.ts +1 -1
- package/dist/{actor-BfQSE0KC.d.ts → actor-ohPC-81x.d.ts} +5 -5
- package/dist/{actor-BfQSE0KC.d.ts.map → actor-ohPC-81x.d.ts.map} +1 -1
- package/dist/actor-react.d.ts +3 -3
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +1 -1
- package/dist/{ai-Cai-lCbj.d.ts → ai-CrEf6p_W.d.ts} +73 -14
- package/dist/ai-CrEf6p_W.d.ts.map +1 -0
- package/dist/ai-DgOBltJ_.js +2451 -0
- package/dist/ai-DgOBltJ_.js.map +1 -0
- package/dist/ai-server.d.ts +4 -5
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +788 -296
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +1 -1999
- package/dist/client-BYzHjkwU.js.map +1 -1
- package/dist/{client-BAEABRZB.d.ts → client-CzyacQpJ.d.ts} +9 -9
- package/dist/client-CzyacQpJ.d.ts.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/idempotent-id-BRJVeylj.js +13 -0
- package/dist/idempotent-id-BRJVeylj.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -12
- package/dist/otel.d.ts +1 -1
- package/dist/react.d.ts +13 -13
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js.map +1 -1
- package/dist/reducer-DEMjEY_O.js.map +1 -1
- package/dist/{reducer-BcS9VDKC.d.ts → reducer-otzHjuJj.d.ts} +3 -3
- package/dist/{reducer-BcS9VDKC.d.ts.map → reducer-otzHjuJj.d.ts.map} +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +1 -1
- package/dist/scheduler-vercel.d.ts +2 -2
- package/dist/scheduler-vercel.js +1 -1
- package/dist/{server-CjJSGcF7.js → server-BD5ckxZb.js} +39 -26
- package/dist/server-BD5ckxZb.js.map +1 -0
- package/dist/{server-Bp5Nd1pF.d.ts → server-DbD7IJVK.d.ts} +5 -5
- package/dist/{server-Bp5Nd1pF.d.ts.map → server-DbD7IJVK.d.ts.map} +1 -1
- package/dist/server.d.ts +3 -3
- package/dist/server.js +1 -1
- package/dist/{store-D_yhNdPz.d.ts → store-DyZM6fS5.d.ts} +3 -2
- package/dist/{store-D_yhNdPz.d.ts.map → store-DyZM6fS5.d.ts.map} +1 -1
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.js +1 -1
- package/dist/{store-redis-notify-D2EI6gwX.js → store-redis-notify-BVLUfI3j.js} +14 -13
- package/dist/store-redis-notify-BVLUfI3j.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.js +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/{telemetry-CpeclqB2.d.ts → telemetry-B5jzpy6y.d.ts} +2 -2
- package/dist/telemetry-B5jzpy6y.d.ts.map +1 -0
- package/docs/concepts/04-state.mdx +9 -4
- package/docs/guides/06-ai-agents.mdx +149 -48
- package/docs/reference/01-api.mdx +110 -28
- package/examples/playground/app/agent/[agentId]/agent-client.tsx +20 -28
- package/examples/playground/app/agent/[agentId]/agent-queue.test.tsx +123 -0
- package/examples/playground/app/agent/[agentId]/agent-queue.tsx +37 -43
- package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +44 -24
- package/examples/playground/app/agent/compaction-timeline.test.ts +47 -7
- package/examples/playground/app/agent/compaction-timeline.ts +13 -3
- package/examples/playground/app/chat/[chatId]/chat-client.tsx +1 -5
- package/examples/playground/app/chat/[chatId]/session.ts +17 -2
- package/examples/playground/app/chat/model.test.ts +4 -4
- package/examples/playground/app/chat/model.ts +18 -6
- package/examples/playground/app/chat/server.ts +6 -3
- package/examples/playground/package.json +3 -1
- package/package.json +1 -1
- package/src/ai-client-state.ts +36 -4
- package/src/ai-context-schema.ts +296 -0
- package/src/ai-context.ts +680 -0
- package/src/ai-control-server.ts +183 -135
- package/src/ai-control-state.ts +6 -0
- package/src/ai-control.ts +8 -7
- package/src/ai-coordinator.ts +92 -38
- package/src/ai-id.ts +6 -0
- package/src/ai-input-tokens.ts +75 -0
- package/src/ai-message-projection.ts +474 -0
- package/src/ai-server.ts +247 -336
- package/src/ai-stored-state.ts +484 -0
- package/src/ai.ts +255 -538
- package/src/client.ts +21 -15
- package/src/react.ts +25 -19
- package/src/reducer.ts +2 -1
- package/src/server.ts +73 -56
- package/src/store-redis-core.ts +15 -17
- package/src/store.ts +1 -0
- package/src/telemetry.ts +2 -1
- package/dist/ai-Cai-lCbj.d.ts.map +0 -1
- package/dist/ai-control-CcD4hh3y.js +0 -119
- package/dist/ai-control-CcD4hh3y.js.map +0 -1
- package/dist/ai.js.map +0 -1
- package/dist/client-BAEABRZB.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/server-CjJSGcF7.js.map +0 -1
- package/dist/store-redis-notify-D2EI6gwX.js.map +0 -1
- package/dist/telemetry-CpeclqB2.d.ts.map +0 -1
package/src/ai.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
export type { PendingQueueCommand } from './ai-client-state.ts'
|
|
22
22
|
import { applyControlChanges } from './ai-control-state.ts'
|
|
23
23
|
import { initialControlState } from './ai-control.ts'
|
|
24
|
+
import { AI_EVENT_ID_PREFIX } from './ai-id.ts'
|
|
24
25
|
import type {
|
|
25
26
|
ControlCommit,
|
|
26
27
|
ActiveTurn,
|
|
@@ -42,13 +43,27 @@ import {
|
|
|
42
43
|
interruptUIMessage,
|
|
43
44
|
pauseUIMessage,
|
|
44
45
|
projectUIMessage,
|
|
45
|
-
projectUIMessageStream,
|
|
46
46
|
type UIMessageCursor,
|
|
47
47
|
} from './ai-projector.ts'
|
|
48
48
|
import { ambientToolScopeStorage } from './internal.ts'
|
|
49
|
+
import {
|
|
50
|
+
upsertMessage,
|
|
51
|
+
upsertResponse,
|
|
52
|
+
answerApproval,
|
|
53
|
+
approvalRequestedChunk,
|
|
54
|
+
toolResultChunk,
|
|
55
|
+
advanceProjection,
|
|
56
|
+
projectedTools,
|
|
57
|
+
restoreGenerationBase,
|
|
58
|
+
stopGenerationTools,
|
|
59
|
+
interruptGenerationProjection,
|
|
60
|
+
projectedMessage,
|
|
61
|
+
reduceToolActivity,
|
|
62
|
+
} from './ai-message-projection.ts'
|
|
49
63
|
import { clientStateProjection, type Reducer } from './reducer.ts'
|
|
64
|
+
import { storedAIReducer, type AIStoredReducer } from './ai-stored-state.ts'
|
|
65
|
+
export type { AIStoredState, AIStoredReducer } from './ai-stored-state.ts'
|
|
50
66
|
import {
|
|
51
|
-
appendProgressBatch,
|
|
52
67
|
flattenProgressBatches,
|
|
53
68
|
progressBatches,
|
|
54
69
|
type ProgressBatches,
|
|
@@ -85,7 +100,8 @@ export type GenerationRequestedPayload = {
|
|
|
85
100
|
control?: { turnId: string; version: number }
|
|
86
101
|
messageId: string
|
|
87
102
|
reason: GenerationReason
|
|
88
|
-
responseMessageId
|
|
103
|
+
responseMessageId: string
|
|
104
|
+
sourceGenerationId?: string
|
|
89
105
|
}
|
|
90
106
|
export type RetryGenerationOptions = {
|
|
91
107
|
messageId: string
|
|
@@ -162,6 +178,7 @@ export type ToolResultPayload = {
|
|
|
162
178
|
toolMetadata?: unknown
|
|
163
179
|
}
|
|
164
180
|
export type ApprovalRequestedPayload = {
|
|
181
|
+
requestId: string
|
|
165
182
|
messageId: string
|
|
166
183
|
generationId: string
|
|
167
184
|
approvalId: string
|
|
@@ -170,6 +187,7 @@ export type ApprovalRequestedPayload = {
|
|
|
170
187
|
signature?: string
|
|
171
188
|
}
|
|
172
189
|
export type ApprovalRespondedPayload = {
|
|
190
|
+
requestId: string
|
|
173
191
|
messageId: string
|
|
174
192
|
generationId: string
|
|
175
193
|
approvalId: string
|
|
@@ -177,6 +195,7 @@ export type ApprovalRespondedPayload = {
|
|
|
177
195
|
reason?: string
|
|
178
196
|
}
|
|
179
197
|
export type InputRequestedPayload = {
|
|
198
|
+
requestId: string
|
|
180
199
|
messageId: string
|
|
181
200
|
generationId: string
|
|
182
201
|
inputId: string
|
|
@@ -184,6 +203,7 @@ export type InputRequestedPayload = {
|
|
|
184
203
|
question?: JSONValue
|
|
185
204
|
}
|
|
186
205
|
export type InputRespondedPayload = {
|
|
206
|
+
requestId: string
|
|
187
207
|
messageId: string
|
|
188
208
|
generationId: string
|
|
189
209
|
inputId: string
|
|
@@ -208,6 +228,9 @@ export type CompactionRequestedPayload = {
|
|
|
208
228
|
generationId: string
|
|
209
229
|
throughMessageId: string
|
|
210
230
|
throughIndex?: number
|
|
231
|
+
inputTokenEstimate?: number
|
|
232
|
+
inputTokens?: number
|
|
233
|
+
thresholdTokens?: number
|
|
211
234
|
}
|
|
212
235
|
export type CompactionCompletedPayload<M extends UIMessage> = {
|
|
213
236
|
generationId: string
|
|
@@ -335,9 +358,14 @@ export type AIState<M extends UIMessage = UIMessage> = {
|
|
|
335
358
|
status: AgentStatus
|
|
336
359
|
activeGeneration: ActiveGeneration | null
|
|
337
360
|
activeRequestId: string | null
|
|
361
|
+
activeRequestReason: GenerationReason | null
|
|
362
|
+
activeRequestSourceGenerationId: string | null
|
|
338
363
|
activeResponseMessageId: string | null
|
|
339
364
|
activeProjection: ActiveGenerationProjection<M> | null
|
|
340
|
-
|
|
365
|
+
responseOwners: Record<
|
|
366
|
+
string,
|
|
367
|
+
Pick<GenerationStartedPayload, 'generationId' | 'requestId' | 'attempt'>
|
|
368
|
+
>
|
|
341
369
|
terminalRequestIds?: Record<string, true>
|
|
342
370
|
terminalGenerations?: Record<
|
|
343
371
|
string,
|
|
@@ -357,7 +385,7 @@ export type AgentDefinition<
|
|
|
357
385
|
D extends EventDefs = AIEventDefs<M>,
|
|
358
386
|
> = {
|
|
359
387
|
readonly contract: Contract<D>
|
|
360
|
-
readonly reducer:
|
|
388
|
+
readonly reducer: AIStoredReducer<D, AIState<M>>
|
|
361
389
|
}
|
|
362
390
|
|
|
363
391
|
export type AgentToolEventDefs = EventDefs &
|
|
@@ -625,9 +653,14 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
625
653
|
const parsed = validateMessage(value['message'], messageSchema)
|
|
626
654
|
if (parsed.issues) return parsed
|
|
627
655
|
if (
|
|
628
|
-
(action === '
|
|
629
|
-
|
|
630
|
-
|
|
656
|
+
(action === 'send' || action === 'steer') &&
|
|
657
|
+
(parsed.value.id.length === 0 ||
|
|
658
|
+
parsed.value.id.startsWith(AI_EVENT_ID_PREFIX))
|
|
659
|
+
)
|
|
660
|
+
return issue(
|
|
661
|
+
'AI input IDs must be nonempty and outside the reserved internal prefix',
|
|
662
|
+
)
|
|
663
|
+
if (
|
|
631
664
|
(action === 'steer' &&
|
|
632
665
|
(!stringField(value, 'turnId') ||
|
|
633
666
|
!optionalIndexField(value, 'lastSeenIndex'))) ||
|
|
@@ -762,7 +795,10 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
762
795
|
'ai.generation.requested',
|
|
763
796
|
(value) =>
|
|
764
797
|
stringField(value, 'messageId') &&
|
|
765
|
-
|
|
798
|
+
stringField(value, 'responseMessageId') &&
|
|
799
|
+
optionalStringField(value, 'sourceGenerationId') &&
|
|
800
|
+
(value['reason'] !== 'tool' ||
|
|
801
|
+
stringField(value, 'sourceGenerationId')) &&
|
|
766
802
|
(value['reason'] === 'message' ||
|
|
767
803
|
value['reason'] === 'tool' ||
|
|
768
804
|
value['reason'] === 'input' ||
|
|
@@ -844,6 +880,7 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
844
880
|
'ai.approval.requested': jsonObject(
|
|
845
881
|
'ai.approval.requested',
|
|
846
882
|
(value) =>
|
|
883
|
+
stringField(value, 'requestId') &&
|
|
847
884
|
stringField(value, 'messageId') &&
|
|
848
885
|
stringField(value, 'generationId') &&
|
|
849
886
|
stringField(value, 'approvalId') &&
|
|
@@ -855,6 +892,7 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
855
892
|
'ai.approval.responded': jsonObject(
|
|
856
893
|
'ai.approval.responded',
|
|
857
894
|
(value) =>
|
|
895
|
+
stringField(value, 'requestId') &&
|
|
858
896
|
stringField(value, 'messageId') &&
|
|
859
897
|
stringField(value, 'generationId') &&
|
|
860
898
|
stringField(value, 'approvalId') &&
|
|
@@ -864,6 +902,7 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
864
902
|
'ai.input.requested': jsonObject(
|
|
865
903
|
'ai.input.requested',
|
|
866
904
|
(value) =>
|
|
905
|
+
stringField(value, 'requestId') &&
|
|
867
906
|
stringField(value, 'messageId') &&
|
|
868
907
|
stringField(value, 'generationId') &&
|
|
869
908
|
stringField(value, 'inputId') &&
|
|
@@ -872,6 +911,7 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
872
911
|
'ai.input.responded': jsonObject(
|
|
873
912
|
'ai.input.responded',
|
|
874
913
|
(value) =>
|
|
914
|
+
stringField(value, 'requestId') &&
|
|
875
915
|
stringField(value, 'messageId') &&
|
|
876
916
|
stringField(value, 'generationId') &&
|
|
877
917
|
stringField(value, 'inputId') &&
|
|
@@ -882,7 +922,10 @@ export function createEvents<M extends UIMessage = UIMessage>(options?: {
|
|
|
882
922
|
(value) =>
|
|
883
923
|
stringField(value, 'generationId') &&
|
|
884
924
|
stringField(value, 'throughMessageId') &&
|
|
885
|
-
optionalIndexField(value, 'throughIndex')
|
|
925
|
+
optionalIndexField(value, 'throughIndex') &&
|
|
926
|
+
optionalIndexField(value, 'inputTokenEstimate') &&
|
|
927
|
+
optionalIndexField(value, 'inputTokens') &&
|
|
928
|
+
optionalIndexField(value, 'thresholdTokens'),
|
|
886
929
|
),
|
|
887
930
|
'ai.compaction.completed': compactionPayloadSchema(messageSchema),
|
|
888
931
|
'ai.model.metadata.requested': jsonObject(
|
|
@@ -919,9 +962,11 @@ const initialState = <M extends UIMessage>(): AIState<M> => ({
|
|
|
919
962
|
status: 'idle',
|
|
920
963
|
activeGeneration: null,
|
|
921
964
|
activeRequestId: null,
|
|
965
|
+
activeRequestReason: null,
|
|
966
|
+
activeRequestSourceGenerationId: null,
|
|
922
967
|
activeResponseMessageId: null,
|
|
923
968
|
activeProjection: null,
|
|
924
|
-
|
|
969
|
+
responseOwners: {},
|
|
925
970
|
pendingApprovals: [],
|
|
926
971
|
pendingInputs: [],
|
|
927
972
|
tools: [],
|
|
@@ -931,62 +976,6 @@ const initialState = <M extends UIMessage>(): AIState<M> => ({
|
|
|
931
976
|
error: null,
|
|
932
977
|
})
|
|
933
978
|
|
|
934
|
-
const upsertMessage = <M extends UIMessage>(messages: M[], message: M): M[] => {
|
|
935
|
-
const index = messages.findIndex((candidate) => candidate.id === message.id)
|
|
936
|
-
if (index === -1) return [...messages, message]
|
|
937
|
-
const next = [...messages]
|
|
938
|
-
next[index] = message
|
|
939
|
-
return next
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
const upsertResponse = <M extends UIMessage>(options: {
|
|
943
|
-
messages: M[]
|
|
944
|
-
message: M
|
|
945
|
-
inputId: string
|
|
946
|
-
}): M[] => {
|
|
947
|
-
const { messages, message, inputId } = options
|
|
948
|
-
if (messages.some((item) => item.id === message.id))
|
|
949
|
-
return upsertMessage(messages, message)
|
|
950
|
-
const inputIndex = messages.findIndex((item) => item.id === inputId)
|
|
951
|
-
if (inputIndex === -1) return [...messages, message]
|
|
952
|
-
return [
|
|
953
|
-
...messages.slice(0, inputIndex + 1),
|
|
954
|
-
message,
|
|
955
|
-
...messages.slice(inputIndex + 1),
|
|
956
|
-
]
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
const answerApproval = <M extends UIMessage>(
|
|
960
|
-
messages: M[],
|
|
961
|
-
response: ApprovalRespondedPayload,
|
|
962
|
-
): M[] =>
|
|
963
|
-
messages.map((message) => {
|
|
964
|
-
if (message.id !== response.messageId) return message
|
|
965
|
-
let changed = false
|
|
966
|
-
const parts = message.parts.map((part) => {
|
|
967
|
-
const candidate = part as unknown
|
|
968
|
-
if (
|
|
969
|
-
!isRecord(candidate) ||
|
|
970
|
-
candidate['state'] !== 'approval-requested' ||
|
|
971
|
-
!isRecord(candidate['approval']) ||
|
|
972
|
-
candidate['approval']['id'] !== response.approvalId
|
|
973
|
-
) {
|
|
974
|
-
return part
|
|
975
|
-
}
|
|
976
|
-
changed = true
|
|
977
|
-
return {
|
|
978
|
-
...part,
|
|
979
|
-
state: 'approval-responded',
|
|
980
|
-
approval: {
|
|
981
|
-
...candidate['approval'],
|
|
982
|
-
approved: response.approved,
|
|
983
|
-
...(response.reason === undefined ? {} : { reason: response.reason }),
|
|
984
|
-
},
|
|
985
|
-
} as typeof part
|
|
986
|
-
})
|
|
987
|
-
return changed ? ({ ...message, parts } as M) : message
|
|
988
|
-
})
|
|
989
|
-
|
|
990
979
|
const projectMessageChunks = <M extends UIMessage>(
|
|
991
980
|
messages: M[],
|
|
992
981
|
messageId: string,
|
|
@@ -998,90 +987,6 @@ const projectMessageChunks = <M extends UIMessage>(
|
|
|
998
987
|
: message,
|
|
999
988
|
)
|
|
1000
989
|
|
|
1001
|
-
const approvalRequestedChunk = (
|
|
1002
|
-
payload: ApprovalRequestedPayload,
|
|
1003
|
-
): UIMessageChunk => ({
|
|
1004
|
-
type: 'tool-approval-request',
|
|
1005
|
-
approvalId: payload.approvalId,
|
|
1006
|
-
toolCallId: payload.toolCallId,
|
|
1007
|
-
...(payload.isAutomatic === undefined
|
|
1008
|
-
? {}
|
|
1009
|
-
: { isAutomatic: payload.isAutomatic }),
|
|
1010
|
-
...(payload.signature === undefined ? {} : { signature: payload.signature }),
|
|
1011
|
-
})
|
|
1012
|
-
|
|
1013
|
-
const approvalRespondedChunk = (
|
|
1014
|
-
payload: ApprovalRespondedPayload,
|
|
1015
|
-
): UIMessageChunk => ({
|
|
1016
|
-
type: 'tool-approval-response',
|
|
1017
|
-
approvalId: payload.approvalId,
|
|
1018
|
-
approved: payload.approved,
|
|
1019
|
-
...(payload.reason === undefined ? {} : { reason: payload.reason }),
|
|
1020
|
-
})
|
|
1021
|
-
|
|
1022
|
-
const toolResultChunk = (payload: ToolResultPayload): UIMessageChunk => {
|
|
1023
|
-
if (payload.phase === 'input') {
|
|
1024
|
-
return {
|
|
1025
|
-
type: 'tool-input-error',
|
|
1026
|
-
toolCallId: payload.toolCallId,
|
|
1027
|
-
toolName: payload.toolName ?? 'unknown',
|
|
1028
|
-
input: payload.rawInput ?? payload.input,
|
|
1029
|
-
errorText: payload.error ?? 'Invalid tool input',
|
|
1030
|
-
...(payload.dynamic === undefined ? {} : { dynamic: payload.dynamic }),
|
|
1031
|
-
...(payload.providerExecuted === undefined
|
|
1032
|
-
? {}
|
|
1033
|
-
: { providerExecuted: payload.providerExecuted }),
|
|
1034
|
-
...(payload.providerMetadata === undefined
|
|
1035
|
-
? {}
|
|
1036
|
-
: { providerMetadata: payload.providerMetadata }),
|
|
1037
|
-
...(payload.toolMetadata === undefined
|
|
1038
|
-
? {}
|
|
1039
|
-
: { toolMetadata: payload.toolMetadata }),
|
|
1040
|
-
} as UIMessageChunk
|
|
1041
|
-
}
|
|
1042
|
-
if (payload.denied === true) {
|
|
1043
|
-
return {
|
|
1044
|
-
type: 'tool-output-denied',
|
|
1045
|
-
toolCallId: payload.toolCallId,
|
|
1046
|
-
} as UIMessageChunk
|
|
1047
|
-
}
|
|
1048
|
-
if (payload.error !== undefined) {
|
|
1049
|
-
return {
|
|
1050
|
-
type: 'tool-output-error',
|
|
1051
|
-
toolCallId: payload.toolCallId,
|
|
1052
|
-
errorText: payload.error,
|
|
1053
|
-
...(payload.dynamic === undefined ? {} : { dynamic: payload.dynamic }),
|
|
1054
|
-
...(payload.providerExecuted === undefined
|
|
1055
|
-
? {}
|
|
1056
|
-
: { providerExecuted: payload.providerExecuted }),
|
|
1057
|
-
...(payload.providerMetadata === undefined
|
|
1058
|
-
? {}
|
|
1059
|
-
: { providerMetadata: payload.providerMetadata }),
|
|
1060
|
-
...(payload.toolMetadata === undefined
|
|
1061
|
-
? {}
|
|
1062
|
-
: { toolMetadata: payload.toolMetadata }),
|
|
1063
|
-
} as UIMessageChunk
|
|
1064
|
-
}
|
|
1065
|
-
return {
|
|
1066
|
-
type: 'tool-output-available',
|
|
1067
|
-
toolCallId: payload.toolCallId,
|
|
1068
|
-
output: payload.output,
|
|
1069
|
-
...(payload.preliminary === undefined
|
|
1070
|
-
? {}
|
|
1071
|
-
: { preliminary: payload.preliminary }),
|
|
1072
|
-
...(payload.dynamic === undefined ? {} : { dynamic: payload.dynamic }),
|
|
1073
|
-
...(payload.providerExecuted === undefined
|
|
1074
|
-
? {}
|
|
1075
|
-
: { providerExecuted: payload.providerExecuted }),
|
|
1076
|
-
...(payload.providerMetadata === undefined
|
|
1077
|
-
? {}
|
|
1078
|
-
: { providerMetadata: payload.providerMetadata }),
|
|
1079
|
-
...(payload.toolMetadata === undefined
|
|
1080
|
-
? {}
|
|
1081
|
-
: { toolMetadata: payload.toolMetadata }),
|
|
1082
|
-
} as UIMessageChunk
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
990
|
const waitingStatus = <M extends UIMessage>(state: AIState<M>): AgentStatus => {
|
|
1086
991
|
if (state.pendingApprovals.length > 0 || state.pendingInputs.length > 0) {
|
|
1087
992
|
return 'waiting'
|
|
@@ -1101,49 +1006,16 @@ const lifecycleStatus = <M extends UIMessage>(
|
|
|
1101
1006
|
const isStaleGeneration = <M extends UIMessage>(
|
|
1102
1007
|
state: AIState<M>,
|
|
1103
1008
|
messageId: string,
|
|
1104
|
-
generationId: string,
|
|
1009
|
+
owner: { generationId: string; requestId: string },
|
|
1105
1010
|
): boolean => {
|
|
1106
|
-
const current = state.
|
|
1107
|
-
return
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
): { message: M; cursor: UIMessageCursor } => {
|
|
1113
|
-
const projectionEvents = flattenProgressBatches(projection.batches)
|
|
1114
|
-
for (const event of projection.toolEvents) {
|
|
1115
|
-
if (event.type === 'ai.tool.result') {
|
|
1116
|
-
projectionEvents.push({
|
|
1117
|
-
index: event.index,
|
|
1118
|
-
chunks: [toolResultChunk(event.payload)],
|
|
1119
|
-
})
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
for (const event of projection.approvalEvents) {
|
|
1123
|
-
projectionEvents.push({
|
|
1124
|
-
index: event.index,
|
|
1125
|
-
chunks: [
|
|
1126
|
-
event.type === 'ai.approval.requested'
|
|
1127
|
-
? approvalRequestedChunk(event.payload)
|
|
1128
|
-
: approvalRespondedChunk(event.payload),
|
|
1129
|
-
],
|
|
1130
|
-
})
|
|
1131
|
-
}
|
|
1132
|
-
return projectUIMessageStream({
|
|
1133
|
-
messageId: projection.responseMessageId,
|
|
1134
|
-
...(projection.baseMessage === undefined
|
|
1135
|
-
? {}
|
|
1136
|
-
: { base: projection.baseMessage }),
|
|
1137
|
-
chunks: projectionEvents
|
|
1138
|
-
.toSorted((left, right) => left.index - right.index)
|
|
1139
|
-
.flatMap((event) => event.chunks),
|
|
1140
|
-
})
|
|
1011
|
+
const current = state.responseOwners[messageId]
|
|
1012
|
+
return (
|
|
1013
|
+
current !== undefined &&
|
|
1014
|
+
(current.generationId !== owner.generationId ||
|
|
1015
|
+
current.requestId !== owner.requestId)
|
|
1016
|
+
)
|
|
1141
1017
|
}
|
|
1142
1018
|
|
|
1143
|
-
const projectedMessage = <M extends UIMessage>(
|
|
1144
|
-
projection: ActiveGenerationProjection<M>,
|
|
1145
|
-
): M => projectedMessageStream(projection).message
|
|
1146
|
-
|
|
1147
1019
|
const projectedResponse = <M extends UIMessage>(options: {
|
|
1148
1020
|
state: AIState<M>
|
|
1149
1021
|
projection: ActiveGenerationProjection<M>
|
|
@@ -1159,220 +1031,13 @@ const projectedResponse = <M extends UIMessage>(options: {
|
|
|
1159
1031
|
: message
|
|
1160
1032
|
}
|
|
1161
1033
|
|
|
1162
|
-
const reduceToolActivity = (
|
|
1163
|
-
tools: ToolActivity[],
|
|
1164
|
-
event:
|
|
1165
|
-
| { type: 'ai.tool.called'; payload: ToolCalledPayload }
|
|
1166
|
-
| { type: 'ai.tool.result'; payload: ToolResultPayload },
|
|
1167
|
-
): ToolActivity[] => {
|
|
1168
|
-
if (event.type === 'ai.tool.called') {
|
|
1169
|
-
const payload = event.payload
|
|
1170
|
-
const { providerMetadata, ...called } = payload
|
|
1171
|
-
const activity: ToolActivity = {
|
|
1172
|
-
...called,
|
|
1173
|
-
...(providerMetadata === undefined
|
|
1174
|
-
? {}
|
|
1175
|
-
: { callProviderMetadata: providerMetadata }),
|
|
1176
|
-
status: 'running',
|
|
1177
|
-
}
|
|
1178
|
-
return [
|
|
1179
|
-
...tools.filter(
|
|
1180
|
-
(candidate) =>
|
|
1181
|
-
candidate.generationId !== payload.generationId ||
|
|
1182
|
-
candidate.toolCallId !== payload.toolCallId,
|
|
1183
|
-
),
|
|
1184
|
-
activity,
|
|
1185
|
-
]
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
const payload = event.payload
|
|
1189
|
-
const existing = tools.find(
|
|
1190
|
-
(candidate) =>
|
|
1191
|
-
candidate.generationId === payload.generationId &&
|
|
1192
|
-
candidate.toolCallId === payload.toolCallId,
|
|
1193
|
-
)
|
|
1194
|
-
const toolName = payload.toolName ?? existing?.toolName
|
|
1195
|
-
const input = payload.input === undefined ? existing?.input : payload.input
|
|
1196
|
-
const dynamic = payload.dynamic ?? existing?.dynamic
|
|
1197
|
-
const providerExecuted =
|
|
1198
|
-
payload.providerExecuted ?? existing?.providerExecuted
|
|
1199
|
-
const toolMetadata = payload.toolMetadata ?? existing?.toolMetadata
|
|
1200
|
-
const resultProviderMetadata =
|
|
1201
|
-
payload.providerMetadata ?? existing?.resultProviderMetadata
|
|
1202
|
-
const activity: ToolActivity = {
|
|
1203
|
-
requestId: payload.requestId,
|
|
1204
|
-
messageId: payload.messageId,
|
|
1205
|
-
generationId: payload.generationId,
|
|
1206
|
-
toolCallId: payload.toolCallId,
|
|
1207
|
-
...(toolName === undefined ? {} : { toolName }),
|
|
1208
|
-
...(input === undefined ? {} : { input }),
|
|
1209
|
-
...(payload.rawInput === undefined ? {} : { rawInput: payload.rawInput }),
|
|
1210
|
-
...(payload.output === undefined ? {} : { output: payload.output }),
|
|
1211
|
-
...(payload.error === undefined ? {} : { error: payload.error }),
|
|
1212
|
-
...(payload.preliminary === undefined
|
|
1213
|
-
? {}
|
|
1214
|
-
: { preliminary: payload.preliminary }),
|
|
1215
|
-
...(payload.phase === undefined ? {} : { phase: payload.phase }),
|
|
1216
|
-
...(dynamic === undefined ? {} : { dynamic }),
|
|
1217
|
-
...(providerExecuted === undefined ? {} : { providerExecuted }),
|
|
1218
|
-
...(existing?.callProviderMetadata === undefined
|
|
1219
|
-
? {}
|
|
1220
|
-
: { callProviderMetadata: existing.callProviderMetadata }),
|
|
1221
|
-
...(resultProviderMetadata === undefined ? {} : { resultProviderMetadata }),
|
|
1222
|
-
...(toolMetadata === undefined ? {} : { toolMetadata }),
|
|
1223
|
-
...(existing?.title === undefined ? {} : { title: existing.title }),
|
|
1224
|
-
status: payload.denied
|
|
1225
|
-
? 'denied'
|
|
1226
|
-
: payload.error
|
|
1227
|
-
? 'failed'
|
|
1228
|
-
: payload.preliminary
|
|
1229
|
-
? 'running'
|
|
1230
|
-
: 'completed',
|
|
1231
|
-
}
|
|
1232
|
-
return [
|
|
1233
|
-
...tools.filter(
|
|
1234
|
-
(candidate) =>
|
|
1235
|
-
candidate.generationId !== payload.generationId ||
|
|
1236
|
-
candidate.toolCallId !== payload.toolCallId,
|
|
1237
|
-
),
|
|
1238
|
-
activity,
|
|
1239
|
-
]
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
const projectedTools = <M extends UIMessage>(
|
|
1243
|
-
projection: ActiveGenerationProjection<M>,
|
|
1244
|
-
): ToolActivity[] =>
|
|
1245
|
-
projection.toolEvents.reduce(
|
|
1246
|
-
(tools, event) => reduceToolActivity(tools, event),
|
|
1247
|
-
projection.baseTools,
|
|
1248
|
-
)
|
|
1249
|
-
|
|
1250
|
-
const restoreGenerationBase = <M extends UIMessage>(
|
|
1251
|
-
state: AIState<M>,
|
|
1252
|
-
generationId: string,
|
|
1253
|
-
responseMessageId: string,
|
|
1254
|
-
reason: 'interrupted' | 'superseded',
|
|
1255
|
-
): AIState<M> => {
|
|
1256
|
-
const projection =
|
|
1257
|
-
state.activeProjection?.generationId === generationId
|
|
1258
|
-
? state.activeProjection
|
|
1259
|
-
: null
|
|
1260
|
-
return {
|
|
1261
|
-
...state,
|
|
1262
|
-
messages:
|
|
1263
|
-
projection?.baseMessage === undefined
|
|
1264
|
-
? state.messages.filter((message) => message.id !== responseMessageId)
|
|
1265
|
-
: upsertMessage(state.messages, projection.baseMessage),
|
|
1266
|
-
tools:
|
|
1267
|
-
projection === null
|
|
1268
|
-
? state.tools.filter(
|
|
1269
|
-
(activity) => activity.generationId !== generationId,
|
|
1270
|
-
)
|
|
1271
|
-
: projection.baseTools,
|
|
1272
|
-
pendingApprovals: state.pendingApprovals.filter(
|
|
1273
|
-
(approval) => approval.generationId !== generationId,
|
|
1274
|
-
),
|
|
1275
|
-
pendingInputs: state.pendingInputs.filter(
|
|
1276
|
-
(input) => input.generationId !== generationId,
|
|
1277
|
-
),
|
|
1278
|
-
activeGeneration: null,
|
|
1279
|
-
activeProjection: null,
|
|
1280
|
-
terminalGenerations: {
|
|
1281
|
-
...state.terminalGenerations,
|
|
1282
|
-
[generationId]: reason,
|
|
1283
|
-
},
|
|
1284
|
-
compaction:
|
|
1285
|
-
projection === null
|
|
1286
|
-
? state.compaction?.generationId === generationId
|
|
1287
|
-
? null
|
|
1288
|
-
: state.compaction
|
|
1289
|
-
: (projection.baseCompaction ?? null),
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
const stopGenerationTools = (
|
|
1294
|
-
tools: ToolActivity[],
|
|
1295
|
-
generationId: string | undefined,
|
|
1296
|
-
responseMessageId: string,
|
|
1297
|
-
error: string,
|
|
1298
|
-
): ToolActivity[] =>
|
|
1299
|
-
tools.map((activity) =>
|
|
1300
|
-
activity.status === 'running' &&
|
|
1301
|
-
(generationId === undefined
|
|
1302
|
-
? activity.messageId === responseMessageId
|
|
1303
|
-
: activity.generationId === generationId)
|
|
1304
|
-
? { ...activity, status: 'failed', error, preliminary: false }
|
|
1305
|
-
: activity,
|
|
1306
|
-
)
|
|
1307
|
-
|
|
1308
|
-
const interruptGenerationProjection = <M extends UIMessage>(
|
|
1309
|
-
state: AIState<M>,
|
|
1310
|
-
generationId: string,
|
|
1311
|
-
responseMessageId: string,
|
|
1312
|
-
cutoff: number,
|
|
1313
|
-
): AIState<M> | null => {
|
|
1314
|
-
const projection =
|
|
1315
|
-
state.activeProjection?.generationId === generationId
|
|
1316
|
-
? state.activeProjection
|
|
1317
|
-
: null
|
|
1318
|
-
if (projection === null) return null
|
|
1319
|
-
const retained: ActiveGenerationProjection<M> = {
|
|
1320
|
-
...projection,
|
|
1321
|
-
batches: progressBatches(
|
|
1322
|
-
flattenProgressBatches(projection.batches).filter(
|
|
1323
|
-
(batch) => batch.index <= cutoff,
|
|
1324
|
-
),
|
|
1325
|
-
),
|
|
1326
|
-
toolEvents: projection.toolEvents.filter(
|
|
1327
|
-
(toolEvent) => toolEvent.index <= cutoff,
|
|
1328
|
-
),
|
|
1329
|
-
approvalEvents: projection.approvalEvents.filter(
|
|
1330
|
-
(approvalEvent) => approvalEvent.index <= cutoff,
|
|
1331
|
-
),
|
|
1332
|
-
}
|
|
1333
|
-
const shouldProject =
|
|
1334
|
-
retained.baseMessage !== undefined || retained.batches.length > 0
|
|
1335
|
-
const restored = restoreGenerationBase(
|
|
1336
|
-
state,
|
|
1337
|
-
generationId,
|
|
1338
|
-
responseMessageId,
|
|
1339
|
-
'interrupted',
|
|
1340
|
-
)
|
|
1341
|
-
return {
|
|
1342
|
-
...restored,
|
|
1343
|
-
messages: shouldProject
|
|
1344
|
-
? upsertMessage(
|
|
1345
|
-
state.messages,
|
|
1346
|
-
interruptUIMessage(projectedMessage(retained)),
|
|
1347
|
-
)
|
|
1348
|
-
: restored.messages,
|
|
1349
|
-
tools: stopGenerationTools(
|
|
1350
|
-
projectedTools(retained),
|
|
1351
|
-
generationId,
|
|
1352
|
-
responseMessageId,
|
|
1353
|
-
'Tool execution was interrupted.',
|
|
1354
|
-
),
|
|
1355
|
-
usage:
|
|
1356
|
-
projection.completionIndex === undefined ||
|
|
1357
|
-
projection.completionIndex <= cutoff
|
|
1358
|
-
? restored.usage
|
|
1359
|
-
: restored.usage.filter((entry) => entry.generationId !== generationId),
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
const generationRequestId = (generationId: string): string | undefined => {
|
|
1364
|
-
const marker = ':generation:'
|
|
1365
|
-
const markerIndex = generationId.lastIndexOf(marker)
|
|
1366
|
-
return markerIndex === -1 ? undefined : generationId.slice(0, markerIndex)
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
1034
|
const terminalGenerationReason = <M extends UIMessage>(
|
|
1370
1035
|
state: AIState<M>,
|
|
1371
1036
|
generationId: string,
|
|
1037
|
+
requestId?: string,
|
|
1372
1038
|
): 'completed' | 'failed' | 'interrupted' | 'superseded' | undefined => {
|
|
1373
1039
|
const terminal = state.terminalGenerations?.[generationId]
|
|
1374
1040
|
if (terminal !== undefined) return terminal
|
|
1375
|
-
const requestId = generationRequestId(generationId)
|
|
1376
1041
|
return requestId !== undefined &&
|
|
1377
1042
|
state.terminalRequestIds?.[requestId] === true
|
|
1378
1043
|
? 'interrupted'
|
|
@@ -1429,6 +1094,8 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1429
1094
|
...visible,
|
|
1430
1095
|
status,
|
|
1431
1096
|
activeRequestId: commit.view.requestId,
|
|
1097
|
+
activeRequestReason: commit.view.requestReason,
|
|
1098
|
+
activeRequestSourceGenerationId: commit.view.sourceGenerationId,
|
|
1432
1099
|
activeResponseMessageId: commit.view.responseMessageId,
|
|
1433
1100
|
}
|
|
1434
1101
|
}
|
|
@@ -1548,6 +1215,8 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1548
1215
|
: state.compaction,
|
|
1549
1216
|
activeGeneration: null,
|
|
1550
1217
|
activeRequestId: null,
|
|
1218
|
+
activeRequestReason: null,
|
|
1219
|
+
activeRequestSourceGenerationId: null,
|
|
1551
1220
|
activeResponseMessageId: null,
|
|
1552
1221
|
activeProjection: null,
|
|
1553
1222
|
}
|
|
@@ -1564,17 +1233,20 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1564
1233
|
}
|
|
1565
1234
|
case 'ai.message.completed': {
|
|
1566
1235
|
const { messageId } = event.payload as MessageCompletedPayload
|
|
1567
|
-
const
|
|
1236
|
+
const owner = state.responseOwners[messageId]
|
|
1237
|
+
const generationId = owner?.generationId
|
|
1238
|
+
const requestId = owner?.requestId
|
|
1568
1239
|
if (
|
|
1569
1240
|
generationId === undefined ||
|
|
1570
|
-
terminalGenerationReason(state, generationId) !== undefined
|
|
1241
|
+
terminalGenerationReason(state, generationId, requestId) !== undefined
|
|
1571
1242
|
) {
|
|
1572
1243
|
return state
|
|
1573
1244
|
}
|
|
1574
|
-
const requestId = generationRequestId(generationId)
|
|
1575
1245
|
return {
|
|
1576
1246
|
...state,
|
|
1577
1247
|
activeRequestId: null,
|
|
1248
|
+
activeRequestReason: null,
|
|
1249
|
+
activeRequestSourceGenerationId: null,
|
|
1578
1250
|
activeResponseMessageId: null,
|
|
1579
1251
|
activeProjection:
|
|
1580
1252
|
state.activeProjection?.generationId === generationId
|
|
@@ -1597,18 +1269,10 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1597
1269
|
case 'ai.generation.requested': {
|
|
1598
1270
|
const payload = event.payload as GenerationRequestedPayload
|
|
1599
1271
|
const schedulesToolContinuation = payload.reason === 'tool'
|
|
1600
|
-
const responseMessageId =
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
: payload.messageId)
|
|
1605
|
-
const ownerGenerationId =
|
|
1606
|
-
state.responseGenerationIds[responseMessageId] ??
|
|
1607
|
-
state.activeGeneration?.generationId
|
|
1608
|
-
const ownerRequestId =
|
|
1609
|
-
ownerGenerationId === undefined
|
|
1610
|
-
? undefined
|
|
1611
|
-
: generationRequestId(ownerGenerationId)
|
|
1272
|
+
const responseMessageId = payload.responseMessageId
|
|
1273
|
+
const owner = state.responseOwners[responseMessageId]
|
|
1274
|
+
const ownerGenerationId = owner?.generationId
|
|
1275
|
+
const ownerRequestId = owner?.requestId
|
|
1612
1276
|
const requestId = (event as { id?: string }).id
|
|
1613
1277
|
if (
|
|
1614
1278
|
requestId !== undefined &&
|
|
@@ -1621,30 +1285,35 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1621
1285
|
payload.reason === 'message' ||
|
|
1622
1286
|
(payload.reason === 'tool'
|
|
1623
1287
|
? ownerGenerationId !== undefined &&
|
|
1624
|
-
|
|
1288
|
+
payload.sourceGenerationId === ownerGenerationId &&
|
|
1625
1289
|
state.activeRequestId === ownerRequestId &&
|
|
1626
1290
|
state.status !== 'failed'
|
|
1627
1291
|
: payload.reason === 'retry'
|
|
1628
1292
|
? state.status === 'failed'
|
|
1629
1293
|
: ownerGenerationId !== undefined &&
|
|
1630
|
-
|
|
1631
|
-
`ai.generate:input:${encodeURIComponent(responseMessageId)}:${encodeURIComponent(ownerGenerationId)}:`,
|
|
1632
|
-
) === true &&
|
|
1294
|
+
payload.sourceGenerationId === ownerGenerationId &&
|
|
1633
1295
|
state.activeRequestId === ownerRequestId &&
|
|
1634
1296
|
state.status !== 'failed')
|
|
1635
1297
|
if (!acceptsRequest) return state
|
|
1298
|
+
const base =
|
|
1299
|
+
payload.reason === 'retry' &&
|
|
1300
|
+
state.activeProjection &&
|
|
1301
|
+
state.activeProjection.completionIndex === undefined
|
|
1302
|
+
? restoreGenerationBase(
|
|
1303
|
+
state,
|
|
1304
|
+
state.activeProjection.generationId,
|
|
1305
|
+
responseMessageId,
|
|
1306
|
+
'failed',
|
|
1307
|
+
)
|
|
1308
|
+
: state
|
|
1636
1309
|
return {
|
|
1637
|
-
...
|
|
1638
|
-
messages:
|
|
1639
|
-
payload.reason === 'retry' && payload.responseMessageId !== undefined
|
|
1640
|
-
? state.messages.filter(
|
|
1641
|
-
(message) => message.id !== payload.responseMessageId,
|
|
1642
|
-
)
|
|
1643
|
-
: state.messages,
|
|
1310
|
+
...base,
|
|
1644
1311
|
activeProjection:
|
|
1645
1312
|
payload.reason === 'retry' ? null : state.activeProjection,
|
|
1646
1313
|
status: schedulesToolContinuation ? state.status : 'generating',
|
|
1647
1314
|
activeRequestId: requestId ?? null,
|
|
1315
|
+
activeRequestReason: payload.reason,
|
|
1316
|
+
activeRequestSourceGenerationId: payload.sourceGenerationId ?? null,
|
|
1648
1317
|
activeResponseMessageId: responseMessageId,
|
|
1649
1318
|
error: schedulesToolContinuation ? state.error : null,
|
|
1650
1319
|
}
|
|
@@ -1653,7 +1322,11 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1653
1322
|
const payload = event.payload as GenerationStartedPayload
|
|
1654
1323
|
if (
|
|
1655
1324
|
state.terminalRequestIds?.[payload.requestId] === true ||
|
|
1656
|
-
terminalGenerationReason(
|
|
1325
|
+
terminalGenerationReason(
|
|
1326
|
+
state,
|
|
1327
|
+
payload.generationId,
|
|
1328
|
+
payload.requestId,
|
|
1329
|
+
) !== undefined
|
|
1657
1330
|
) {
|
|
1658
1331
|
return state
|
|
1659
1332
|
}
|
|
@@ -1663,31 +1336,26 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1663
1336
|
) {
|
|
1664
1337
|
return state
|
|
1665
1338
|
}
|
|
1666
|
-
const currentOwner =
|
|
1667
|
-
state.responseGenerationIds[payload.responseMessageId]
|
|
1339
|
+
const currentOwner = state.responseOwners[payload.responseMessageId]
|
|
1668
1340
|
const currentTerminal =
|
|
1669
1341
|
currentOwner === undefined
|
|
1670
1342
|
? undefined
|
|
1671
|
-
: terminalGenerationReason(
|
|
1343
|
+
: terminalGenerationReason(
|
|
1344
|
+
state,
|
|
1345
|
+
currentOwner.generationId,
|
|
1346
|
+
currentOwner.requestId,
|
|
1347
|
+
)
|
|
1672
1348
|
if (
|
|
1673
1349
|
currentTerminal === 'completed' ||
|
|
1674
1350
|
currentTerminal === 'interrupted'
|
|
1675
1351
|
) {
|
|
1676
1352
|
return state
|
|
1677
1353
|
}
|
|
1678
|
-
const marker = ':generation:'
|
|
1679
|
-
const currentAttempt = currentOwner?.startsWith(
|
|
1680
|
-
`${payload.requestId}${marker}`,
|
|
1681
|
-
)
|
|
1682
|
-
? Number(currentOwner.slice(`${payload.requestId}${marker}`.length))
|
|
1683
|
-
: undefined
|
|
1684
1354
|
if (
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
) {
|
|
1355
|
+
currentOwner?.requestId === payload.requestId &&
|
|
1356
|
+
currentOwner.attempt >= payload.attempt
|
|
1357
|
+
)
|
|
1689
1358
|
return state
|
|
1690
|
-
}
|
|
1691
1359
|
const activeGeneration = state.activeGeneration
|
|
1692
1360
|
const replacesActiveAttempt =
|
|
1693
1361
|
activeGeneration !== null &&
|
|
@@ -1711,9 +1379,13 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1711
1379
|
status: 'generating',
|
|
1712
1380
|
activeGeneration: payload,
|
|
1713
1381
|
activeResponseMessageId: null,
|
|
1714
|
-
|
|
1715
|
-
...baseState.
|
|
1716
|
-
[payload.responseMessageId]:
|
|
1382
|
+
responseOwners: {
|
|
1383
|
+
...baseState.responseOwners,
|
|
1384
|
+
[payload.responseMessageId]: {
|
|
1385
|
+
generationId: payload.generationId,
|
|
1386
|
+
requestId: payload.requestId,
|
|
1387
|
+
attempt: payload.attempt,
|
|
1388
|
+
},
|
|
1717
1389
|
},
|
|
1718
1390
|
activeProjection: {
|
|
1719
1391
|
generationId: payload.generationId,
|
|
@@ -1732,83 +1404,61 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1732
1404
|
case 'ai.generation.progress': {
|
|
1733
1405
|
const payload = event.payload as GenerationProgressPayload
|
|
1734
1406
|
if (state.pausedGenerationIds?.[payload.generationId]) return state
|
|
1735
|
-
if (
|
|
1407
|
+
if (
|
|
1408
|
+
terminalGenerationReason(
|
|
1409
|
+
state,
|
|
1410
|
+
payload.generationId,
|
|
1411
|
+
payload.requestId,
|
|
1412
|
+
) !== undefined
|
|
1413
|
+
) {
|
|
1736
1414
|
return state
|
|
1737
1415
|
}
|
|
1738
1416
|
const activeProjection = state.activeProjection
|
|
1739
1417
|
if (
|
|
1740
1418
|
state.activeGeneration?.generationId !== payload.generationId ||
|
|
1419
|
+
state.activeGeneration.requestId !== payload.requestId ||
|
|
1741
1420
|
activeProjection?.generationId !== payload.generationId
|
|
1742
1421
|
) {
|
|
1743
1422
|
return state
|
|
1744
1423
|
}
|
|
1745
|
-
const
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
})
|
|
1754
|
-
: progressBatches(
|
|
1755
|
-
[
|
|
1756
|
-
...flattenProgressBatches(activeProjection.batches).filter(
|
|
1757
|
-
(batch) => batch.index !== event.index,
|
|
1758
|
-
),
|
|
1759
|
-
{ index: event.index, chunks: payload.chunks },
|
|
1760
|
-
].toSorted((left, right) => left.index - right.index),
|
|
1761
|
-
),
|
|
1762
|
-
}
|
|
1763
|
-
const base = state.messages.find(
|
|
1764
|
-
(message) => message.id === projection.responseMessageId,
|
|
1765
|
-
)
|
|
1766
|
-
const incremental =
|
|
1767
|
-
base !== undefined &&
|
|
1768
|
-
activeProjection.cursor != null &&
|
|
1769
|
-
event.index > activeProjection.cursor.throughIndex
|
|
1770
|
-
const projected = incremental
|
|
1771
|
-
? projectUIMessageStream({
|
|
1772
|
-
messageId: projection.responseMessageId,
|
|
1773
|
-
base,
|
|
1774
|
-
cursor: activeProjection.cursor!.stream,
|
|
1775
|
-
chunks: payload.chunks,
|
|
1776
|
-
})
|
|
1777
|
-
: projectedMessageStream(projection)
|
|
1778
|
-
projection.cursor = {
|
|
1779
|
-
throughIndex: incremental
|
|
1780
|
-
? event.index
|
|
1781
|
-
: Math.max(
|
|
1782
|
-
event.index,
|
|
1783
|
-
projection.batches.tail.at(-1)?.index ?? 0,
|
|
1784
|
-
projection.toolEvents.reduce(
|
|
1785
|
-
(index, entry) => Math.max(index, entry.index),
|
|
1786
|
-
0,
|
|
1787
|
-
),
|
|
1788
|
-
projection.approvalEvents.reduce(
|
|
1789
|
-
(index, entry) => Math.max(index, entry.index),
|
|
1790
|
-
0,
|
|
1791
|
-
),
|
|
1792
|
-
),
|
|
1793
|
-
stream: projected.cursor,
|
|
1794
|
-
}
|
|
1424
|
+
const progress = advanceProjection({
|
|
1425
|
+
projection: activeProjection,
|
|
1426
|
+
base: state.messages.find(
|
|
1427
|
+
(message) => message.id === activeProjection.responseMessageId,
|
|
1428
|
+
),
|
|
1429
|
+
chunks: payload.chunks,
|
|
1430
|
+
index: event.index,
|
|
1431
|
+
})
|
|
1795
1432
|
return {
|
|
1796
1433
|
...state,
|
|
1797
1434
|
messages: upsertResponse({
|
|
1798
1435
|
messages: state.messages,
|
|
1799
|
-
message:
|
|
1436
|
+
message: progress.message,
|
|
1800
1437
|
inputId: state.activeGeneration.messageId,
|
|
1801
1438
|
}),
|
|
1802
|
-
activeProjection:
|
|
1439
|
+
activeProjection: {
|
|
1440
|
+
...activeProjection,
|
|
1441
|
+
batches: progress.batches,
|
|
1442
|
+
cursor: progress.cursor,
|
|
1443
|
+
},
|
|
1803
1444
|
status: 'generating',
|
|
1804
1445
|
}
|
|
1805
1446
|
}
|
|
1806
1447
|
case 'ai.generation.completed': {
|
|
1807
1448
|
const payload = event.payload as GenerationCompletedPayload
|
|
1808
|
-
if (
|
|
1449
|
+
if (
|
|
1450
|
+
terminalGenerationReason(
|
|
1451
|
+
state,
|
|
1452
|
+
payload.generationId,
|
|
1453
|
+
payload.requestId,
|
|
1454
|
+
) !== undefined
|
|
1455
|
+
) {
|
|
1809
1456
|
return state
|
|
1810
1457
|
}
|
|
1811
|
-
if (
|
|
1458
|
+
if (
|
|
1459
|
+
state.activeGeneration?.generationId !== payload.generationId ||
|
|
1460
|
+
state.activeGeneration.requestId !== payload.requestId
|
|
1461
|
+
) {
|
|
1812
1462
|
return state
|
|
1813
1463
|
}
|
|
1814
1464
|
const usage = payload.usage
|
|
@@ -1832,17 +1482,26 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1832
1482
|
}
|
|
1833
1483
|
case 'ai.generation.failed': {
|
|
1834
1484
|
const payload = event.payload as GenerationFailedPayload
|
|
1835
|
-
if (
|
|
1485
|
+
if (
|
|
1486
|
+
terminalGenerationReason(
|
|
1487
|
+
state,
|
|
1488
|
+
payload.generationId,
|
|
1489
|
+
payload.requestId,
|
|
1490
|
+
) !== undefined
|
|
1491
|
+
) {
|
|
1836
1492
|
return state
|
|
1837
1493
|
}
|
|
1838
1494
|
if (
|
|
1839
|
-
state.activeGeneration?.generationId !== payload.generationId
|
|
1495
|
+
(state.activeGeneration?.generationId !== payload.generationId ||
|
|
1496
|
+
state.activeGeneration.requestId !== payload.requestId) &&
|
|
1840
1497
|
!(
|
|
1841
1498
|
payload.stepLimit === true &&
|
|
1842
|
-
state.
|
|
1499
|
+
state.activeRequestReason === 'tool' &&
|
|
1500
|
+
state.responseOwners[payload.responseMessageId]?.requestId ===
|
|
1501
|
+
payload.requestId &&
|
|
1502
|
+
state.responseOwners[payload.responseMessageId]?.generationId ===
|
|
1843
1503
|
payload.generationId &&
|
|
1844
|
-
state.
|
|
1845
|
-
`ai.generate:tools:${payload.generationId}` &&
|
|
1504
|
+
state.activeRequestSourceGenerationId === payload.generationId &&
|
|
1846
1505
|
state.activeResponseMessageId === payload.responseMessageId
|
|
1847
1506
|
)
|
|
1848
1507
|
) {
|
|
@@ -1912,9 +1571,13 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1912
1571
|
}
|
|
1913
1572
|
case 'ai.message.interrupted': {
|
|
1914
1573
|
const payload = event.payload as MessageInterruptedPayload
|
|
1915
|
-
const
|
|
1574
|
+
const owner = state.responseOwners[payload.messageId]
|
|
1575
|
+
const currentGenerationId = owner?.generationId
|
|
1916
1576
|
const targetRequestId =
|
|
1917
|
-
payload.requestId ??
|
|
1577
|
+
payload.requestId ??
|
|
1578
|
+
(owner?.generationId === payload.generationId
|
|
1579
|
+
? owner?.requestId
|
|
1580
|
+
: undefined)
|
|
1918
1581
|
const ownsRequestPhase =
|
|
1919
1582
|
payload.requestId !== undefined &&
|
|
1920
1583
|
state.activeGeneration === null &&
|
|
@@ -1925,7 +1588,7 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1925
1588
|
!ownsRequestPhase &&
|
|
1926
1589
|
(payload.generationId !== undefined
|
|
1927
1590
|
? currentGenerationId !== payload.generationId
|
|
1928
|
-
:
|
|
1591
|
+
: owner?.requestId !== payload.requestId)
|
|
1929
1592
|
) {
|
|
1930
1593
|
return state
|
|
1931
1594
|
}
|
|
@@ -1940,7 +1603,11 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1940
1603
|
const currentTerminal =
|
|
1941
1604
|
currentGenerationId === undefined
|
|
1942
1605
|
? undefined
|
|
1943
|
-
: terminalGenerationReason(
|
|
1606
|
+
: terminalGenerationReason(
|
|
1607
|
+
state,
|
|
1608
|
+
currentGenerationId,
|
|
1609
|
+
owner?.requestId,
|
|
1610
|
+
)
|
|
1944
1611
|
if (
|
|
1945
1612
|
currentTerminal === 'completed' ||
|
|
1946
1613
|
currentTerminal === 'interrupted' ||
|
|
@@ -1970,6 +1637,8 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1970
1637
|
...baseState,
|
|
1971
1638
|
status: 'idle',
|
|
1972
1639
|
activeRequestId: null,
|
|
1640
|
+
activeRequestReason: null,
|
|
1641
|
+
activeRequestSourceGenerationId: null,
|
|
1973
1642
|
activeResponseMessageId: null,
|
|
1974
1643
|
activeProjection: null,
|
|
1975
1644
|
terminalRequestIds: {
|
|
@@ -1990,7 +1659,7 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
1990
1659
|
const targetGenerationId =
|
|
1991
1660
|
payload.generationId ??
|
|
1992
1661
|
(currentGenerationId !== undefined &&
|
|
1993
|
-
|
|
1662
|
+
owner?.requestId === payload.requestId
|
|
1994
1663
|
? currentGenerationId
|
|
1995
1664
|
: undefined)
|
|
1996
1665
|
if (targetGenerationId === undefined) return state
|
|
@@ -2019,7 +1688,8 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2019
1688
|
currentGenerationId === targetGenerationId &&
|
|
2020
1689
|
(state.activeRequestId === null ||
|
|
2021
1690
|
state.activeRequestId === targetRequestId ||
|
|
2022
|
-
state.
|
|
1691
|
+
(state.activeRequestReason === 'tool' &&
|
|
1692
|
+
state.activeRequestSourceGenerationId === targetGenerationId))
|
|
2023
1693
|
const resolvesCurrentGeneration =
|
|
2024
1694
|
currentGenerationId === targetGenerationId &&
|
|
2025
1695
|
currentTerminal === undefined
|
|
@@ -2041,6 +1711,8 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2041
1711
|
const next = {
|
|
2042
1712
|
...baseState,
|
|
2043
1713
|
activeRequestId: null,
|
|
1714
|
+
activeRequestReason: null,
|
|
1715
|
+
activeRequestSourceGenerationId: null,
|
|
2044
1716
|
activeResponseMessageId: null,
|
|
2045
1717
|
activeProjection: null,
|
|
2046
1718
|
messages:
|
|
@@ -2114,6 +1786,8 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2114
1786
|
const next = {
|
|
2115
1787
|
...baseState,
|
|
2116
1788
|
activeRequestId: null,
|
|
1789
|
+
activeRequestReason: null,
|
|
1790
|
+
activeRequestSourceGenerationId: null,
|
|
2117
1791
|
activeResponseMessageId: null,
|
|
2118
1792
|
terminalRequestIds: {
|
|
2119
1793
|
...baseState.terminalRequestIds,
|
|
@@ -2135,8 +1809,12 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2135
1809
|
const payload = event.payload as ToolCalledPayload
|
|
2136
1810
|
const projection = state.activeProjection
|
|
2137
1811
|
if (
|
|
2138
|
-
isStaleGeneration(state, payload.messageId, payload
|
|
2139
|
-
terminalGenerationReason(
|
|
1812
|
+
isStaleGeneration(state, payload.messageId, payload) ||
|
|
1813
|
+
terminalGenerationReason(
|
|
1814
|
+
state,
|
|
1815
|
+
payload.generationId,
|
|
1816
|
+
payload.requestId,
|
|
1817
|
+
) !== undefined
|
|
2140
1818
|
) {
|
|
2141
1819
|
return state
|
|
2142
1820
|
}
|
|
@@ -2181,6 +1859,7 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2181
1859
|
const terminalReason = terminalGenerationReason(
|
|
2182
1860
|
state,
|
|
2183
1861
|
payload.generationId,
|
|
1862
|
+
payload.requestId,
|
|
2184
1863
|
)
|
|
2185
1864
|
const completesFailedTool =
|
|
2186
1865
|
terminalReason === 'failed' &&
|
|
@@ -2194,7 +1873,7 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2194
1873
|
activity.status === 'running',
|
|
2195
1874
|
)
|
|
2196
1875
|
if (
|
|
2197
|
-
isStaleGeneration(state, payload.messageId, payload
|
|
1876
|
+
isStaleGeneration(state, payload.messageId, payload) ||
|
|
2198
1877
|
(terminalReason !== undefined && !completesFailedTool)
|
|
2199
1878
|
) {
|
|
2200
1879
|
return state
|
|
@@ -2266,8 +1945,12 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2266
1945
|
const payload = event.payload as ApprovalRequestedPayload
|
|
2267
1946
|
const projection = state.activeProjection
|
|
2268
1947
|
if (
|
|
2269
|
-
isStaleGeneration(state, payload.messageId, payload
|
|
2270
|
-
terminalGenerationReason(
|
|
1948
|
+
isStaleGeneration(state, payload.messageId, payload) ||
|
|
1949
|
+
terminalGenerationReason(
|
|
1950
|
+
state,
|
|
1951
|
+
payload.generationId,
|
|
1952
|
+
payload.requestId,
|
|
1953
|
+
) !== undefined
|
|
2271
1954
|
) {
|
|
2272
1955
|
return state
|
|
2273
1956
|
}
|
|
@@ -2329,8 +2012,12 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2329
2012
|
case 'ai.approval.responded': {
|
|
2330
2013
|
const payload = event.payload as ApprovalRespondedPayload
|
|
2331
2014
|
if (
|
|
2332
|
-
isStaleGeneration(state, payload.messageId, payload
|
|
2333
|
-
terminalGenerationReason(
|
|
2015
|
+
isStaleGeneration(state, payload.messageId, payload) ||
|
|
2016
|
+
terminalGenerationReason(
|
|
2017
|
+
state,
|
|
2018
|
+
payload.generationId,
|
|
2019
|
+
payload.requestId,
|
|
2020
|
+
) !== undefined
|
|
2334
2021
|
) {
|
|
2335
2022
|
return state
|
|
2336
2023
|
}
|
|
@@ -2398,8 +2085,12 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2398
2085
|
case 'ai.input.requested': {
|
|
2399
2086
|
const payload = event.payload as InputRequestedPayload
|
|
2400
2087
|
if (
|
|
2401
|
-
isStaleGeneration(state, payload.messageId, payload
|
|
2402
|
-
terminalGenerationReason(
|
|
2088
|
+
isStaleGeneration(state, payload.messageId, payload) ||
|
|
2089
|
+
terminalGenerationReason(
|
|
2090
|
+
state,
|
|
2091
|
+
payload.generationId,
|
|
2092
|
+
payload.requestId,
|
|
2093
|
+
) !== undefined
|
|
2403
2094
|
) {
|
|
2404
2095
|
return state
|
|
2405
2096
|
}
|
|
@@ -2420,8 +2111,12 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2420
2111
|
case 'ai.input.responded': {
|
|
2421
2112
|
const payload = event.payload as InputRespondedPayload
|
|
2422
2113
|
if (
|
|
2423
|
-
isStaleGeneration(state, payload.messageId, payload
|
|
2424
|
-
terminalGenerationReason(
|
|
2114
|
+
isStaleGeneration(state, payload.messageId, payload) ||
|
|
2115
|
+
terminalGenerationReason(
|
|
2116
|
+
state,
|
|
2117
|
+
payload.generationId,
|
|
2118
|
+
payload.requestId,
|
|
2119
|
+
) !== undefined
|
|
2425
2120
|
) {
|
|
2426
2121
|
return state
|
|
2427
2122
|
}
|
|
@@ -2455,13 +2150,18 @@ export function reduceAIState<M extends UIMessage>(
|
|
|
2455
2150
|
) {
|
|
2456
2151
|
return state
|
|
2457
2152
|
}
|
|
2153
|
+
const compaction: CompactionState<M> = {
|
|
2154
|
+
status: 'completed',
|
|
2155
|
+
...payload,
|
|
2156
|
+
throughIndex:
|
|
2157
|
+
payload.throughIndex ?? state.activeProjection!.promptThroughIndex!,
|
|
2158
|
+
}
|
|
2458
2159
|
return {
|
|
2459
2160
|
...state,
|
|
2460
|
-
compaction
|
|
2461
|
-
|
|
2462
|
-
...
|
|
2463
|
-
|
|
2464
|
-
payload.throughIndex ?? state.activeProjection!.promptThroughIndex!,
|
|
2161
|
+
compaction,
|
|
2162
|
+
activeProjection: state.activeProjection && {
|
|
2163
|
+
...state.activeProjection,
|
|
2164
|
+
baseCompaction: compaction,
|
|
2465
2165
|
},
|
|
2466
2166
|
}
|
|
2467
2167
|
}
|
|
@@ -2483,22 +2183,31 @@ export function deriveUIMessages<M extends UIMessage = UIMessage>(
|
|
|
2483
2183
|
export function createReducer<D extends EventDefs>(options: {
|
|
2484
2184
|
contract: Contract<D>
|
|
2485
2185
|
name?: string
|
|
2486
|
-
|
|
2186
|
+
fold?: Reducer<D, AIState<AIMessageFrom<D>>>['fold']
|
|
2187
|
+
stateSchema?: StandardSchemaV1<unknown, AIState<AIMessageFrom<D>>>
|
|
2188
|
+
}): AIStoredReducer<D, AIState<AIMessageFrom<D>>> {
|
|
2487
2189
|
type M = AIMessageFrom<D>
|
|
2488
2190
|
const reducer = options.contract
|
|
2489
2191
|
.reducer({
|
|
2490
|
-
name: options.name ?? 'a2.ai.state.
|
|
2192
|
+
name: options.name ?? 'a2.ai.state.v22',
|
|
2491
2193
|
initialState: initialState<M>(),
|
|
2194
|
+
...(options.stateSchema === undefined
|
|
2195
|
+
? {}
|
|
2196
|
+
: { stateSchema: options.stateSchema }),
|
|
2492
2197
|
})
|
|
2493
|
-
.fold((state, event) => reduceAIState(state, event))
|
|
2494
|
-
return {
|
|
2198
|
+
.fold(options.fold ?? ((state, event) => reduceAIState(state, event)))
|
|
2199
|
+
return storedAIReducer({
|
|
2200
|
+
...reducer,
|
|
2201
|
+
[clientStateProjection]: projectAIClientState,
|
|
2202
|
+
})
|
|
2495
2203
|
}
|
|
2496
2204
|
|
|
2497
2205
|
type CommandInput<C> = { type: 'ai.control.requested'; payload: C; id?: string }
|
|
2498
2206
|
type ControlInput<
|
|
2499
2207
|
M extends UIMessage,
|
|
2500
2208
|
A extends ControlCommand<M>['action'],
|
|
2501
|
-
> = CommandInput<Extract<ControlCommand<M>, { action: A }>>
|
|
2209
|
+
> = CommandInput<Extract<ControlCommand<M>, { action: A }>> &
|
|
2210
|
+
(A extends 'send' | 'steer' ? { id: string } : {})
|
|
2502
2211
|
|
|
2503
2212
|
export type AIInputs = {
|
|
2504
2213
|
message<M extends UIMessage>(
|
|
@@ -2515,7 +2224,6 @@ export type AIInputs = {
|
|
|
2515
2224
|
}): ControlInput<UIMessage, 'send-now'>[]
|
|
2516
2225
|
edit<M extends UIMessage>(options: {
|
|
2517
2226
|
message: M
|
|
2518
|
-
expectedRevision: number
|
|
2519
2227
|
}): ControlInput<M, 'edit'>[]
|
|
2520
2228
|
move(options: {
|
|
2521
2229
|
inputId: string
|
|
@@ -2560,7 +2268,7 @@ const messageInput = <M extends UIMessage>(
|
|
|
2560
2268
|
): ControlInput<M, 'send'>[] => [
|
|
2561
2269
|
{
|
|
2562
2270
|
type: 'ai.control.requested',
|
|
2563
|
-
id:
|
|
2271
|
+
id: message.id,
|
|
2564
2272
|
payload: {
|
|
2565
2273
|
action: 'send',
|
|
2566
2274
|
message,
|
|
@@ -2579,7 +2287,13 @@ export const inputs: AIInputs = {
|
|
|
2579
2287
|
move: (options) => commandInput({ action: 'move', ...options }),
|
|
2580
2288
|
},
|
|
2581
2289
|
stop: (options) => commandInput({ action: 'stop', ...options }),
|
|
2582
|
-
steer: (options) =>
|
|
2290
|
+
steer: (options) => [
|
|
2291
|
+
{
|
|
2292
|
+
type: 'ai.control.requested',
|
|
2293
|
+
id: options.message.id,
|
|
2294
|
+
payload: { action: 'steer', ...options },
|
|
2295
|
+
},
|
|
2296
|
+
],
|
|
2583
2297
|
pause: (options) => commandInput({ action: 'pause', ...options }),
|
|
2584
2298
|
resume: () => commandInput({ action: 'resume' }),
|
|
2585
2299
|
message<M extends UIMessage>(message: M, options?: { generate?: boolean }) {
|
|
@@ -2591,19 +2305,19 @@ export const inputs: AIInputs = {
|
|
|
2591
2305
|
approval: (response) => [
|
|
2592
2306
|
{
|
|
2593
2307
|
...commandInput({ action: 'approval', response })[0]!,
|
|
2594
|
-
id: `ai.approval:${encodeURIComponent(response.messageId)}:${encodeURIComponent(response.generationId)}:${encodeURIComponent(response.approvalId)}:response`,
|
|
2308
|
+
id: `ai.approval:${encodeURIComponent(response.requestId)}:${encodeURIComponent(response.messageId)}:${encodeURIComponent(response.generationId)}:${encodeURIComponent(response.approvalId)}:response`,
|
|
2595
2309
|
},
|
|
2596
2310
|
],
|
|
2597
2311
|
input: (response) => [
|
|
2598
2312
|
{
|
|
2599
2313
|
...commandInput({ action: 'input', response })[0]!,
|
|
2600
|
-
id: `ai.input:${encodeURIComponent(response.messageId)}:${encodeURIComponent(response.generationId)}:${encodeURIComponent(response.inputId)}:response`,
|
|
2314
|
+
id: `ai.input:${encodeURIComponent(response.requestId)}:${encodeURIComponent(response.messageId)}:${encodeURIComponent(response.generationId)}:${encodeURIComponent(response.inputId)}:response`,
|
|
2601
2315
|
},
|
|
2602
2316
|
],
|
|
2603
2317
|
requestInput: (request) => [
|
|
2604
2318
|
{
|
|
2605
2319
|
...commandInput({ action: 'request-input', request })[0]!,
|
|
2606
|
-
id: `ai.input:${encodeURIComponent(request.messageId)}:${encodeURIComponent(request.generationId)}:${encodeURIComponent(request.inputId)}:request`,
|
|
2320
|
+
id: `ai.input:${encodeURIComponent(request.requestId)}:${encodeURIComponent(request.messageId)}:${encodeURIComponent(request.generationId)}:${encodeURIComponent(request.inputId)}:request`,
|
|
2607
2321
|
},
|
|
2608
2322
|
],
|
|
2609
2323
|
retry: (request) => [
|
|
@@ -2674,14 +2388,17 @@ export function agent<
|
|
|
2674
2388
|
})
|
|
2675
2389
|
const reducer = agentContract
|
|
2676
2390
|
.reducer({
|
|
2677
|
-
name: options.reducerName ?? 'a2.ai.state.
|
|
2391
|
+
name: options.reducerName ?? 'a2.ai.state.v22',
|
|
2678
2392
|
initialState: initialState<M>(),
|
|
2679
2393
|
})
|
|
2680
2394
|
.fold((state, event) => reduceAIState(state, event))
|
|
2681
2395
|
|
|
2682
2396
|
const definition = {
|
|
2683
2397
|
contract: agentContract,
|
|
2684
|
-
reducer: {
|
|
2398
|
+
reducer: storedAIReducer({
|
|
2399
|
+
...reducer,
|
|
2400
|
+
[clientStateProjection]: projectAIClientState<M>,
|
|
2401
|
+
}),
|
|
2685
2402
|
}
|
|
2686
2403
|
return definition as unknown as AgentDefinition<M, AIEventDefs<M> & E>
|
|
2687
2404
|
}
|