@yolk-sdk/agent 0.1.0-canary.20 → 0.1.0-canary.21

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.
Files changed (55) hide show
  1. package/README.md +21 -1
  2. package/dist/client/state.d.mts +4 -2
  3. package/dist/client/state.d.mts.map +1 -1
  4. package/dist/client/state.mjs +42 -22
  5. package/dist/client/state.mjs.map +1 -1
  6. package/dist/loop/error.d.mts +3 -2
  7. package/dist/loop/error.d.mts.map +1 -1
  8. package/dist/loop/error.mjs +6 -3
  9. package/dist/loop/error.mjs.map +1 -1
  10. package/dist/loop/run.d.mts.map +1 -1
  11. package/dist/loop/run.mjs +17 -3
  12. package/dist/loop/run.mjs.map +1 -1
  13. package/dist/loop/services/loop-config.mjs +1 -1
  14. package/dist/loop/services/loop-config.mjs.map +1 -1
  15. package/dist/protocol/event.d.mts +17 -5
  16. package/dist/protocol/event.d.mts.map +1 -1
  17. package/dist/protocol/event.mjs +24 -3
  18. package/dist/protocol/event.mjs.map +1 -1
  19. package/dist/protocol/index.d.mts +2 -2
  20. package/dist/protocol/index.d.mts.map +1 -1
  21. package/dist/protocol/index.mjs +2 -2
  22. package/dist/providers/anthropic/claude-provider.d.mts.map +1 -1
  23. package/dist/providers/anthropic/claude-provider.mjs +36 -15
  24. package/dist/providers/anthropic/claude-provider.mjs.map +1 -1
  25. package/dist/providers/openai/codex-provider.d.mts.map +1 -1
  26. package/dist/providers/openai/codex-provider.mjs +59 -17
  27. package/dist/providers/openai/codex-provider.mjs.map +1 -1
  28. package/dist/providers/openai/provider.d.mts.map +1 -1
  29. package/dist/providers/openai/provider.mjs +16 -10
  30. package/dist/providers/openai/provider.mjs.map +1 -1
  31. package/dist/providers/provider-error.d.mts +32 -0
  32. package/dist/providers/provider-error.d.mts.map +1 -0
  33. package/dist/providers/provider-error.mjs +91 -0
  34. package/dist/providers/provider-error.mjs.map +1 -0
  35. package/dist/react/chat-core.d.mts +3 -1
  36. package/dist/react/chat-core.d.mts.map +1 -1
  37. package/dist/react/chat-core.mjs +42 -6
  38. package/dist/react/chat-core.mjs.map +1 -1
  39. package/dist/react/chat-items.d.mts +8 -2
  40. package/dist/react/chat-items.d.mts.map +1 -1
  41. package/dist/react/chat-items.mjs +16 -9
  42. package/dist/react/chat-items.mjs.map +1 -1
  43. package/package.json +1 -1
  44. package/src/client/state.ts +43 -18
  45. package/src/loop/error.ts +6 -3
  46. package/src/loop/run.ts +27 -4
  47. package/src/loop/services/loop-config.ts +1 -1
  48. package/src/protocol/event.ts +26 -2
  49. package/src/protocol/index.ts +2 -0
  50. package/src/providers/anthropic/claude-provider.ts +51 -22
  51. package/src/providers/openai/codex-provider.ts +81 -19
  52. package/src/providers/openai/provider.ts +22 -18
  53. package/src/providers/provider-error.ts +213 -0
  54. package/src/react/chat-core.ts +46 -5
  55. package/src/react/chat-items.ts +10 -3
@@ -5,6 +5,8 @@ import { hitlResponseEvent } from "@yolk-sdk/agent/protocol";
5
5
  const initialAgentChatState = {
6
6
  status: "idle",
7
7
  error: null,
8
+ errorInfo: null,
9
+ retryInfo: null,
8
10
  chatMessages: [],
9
11
  sessionEvents: [],
10
12
  seenEventIds: []
@@ -14,17 +16,25 @@ const rememberEvent = (state, event) => event.eventId === void 0 ? state : {
14
16
  ...state,
15
17
  seenEventIds: [...state.seenEventIds, event.eventId]
16
18
  };
19
+ const clearRetryInfo = (state) => state.retryInfo === null ? state : {
20
+ ...state,
21
+ retryInfo: null
22
+ };
17
23
  const reduceAgentChatState = (state, action) => {
18
24
  switch (action._tag) {
19
25
  case "HydrateMessage": return {
20
26
  ...state,
21
27
  chatMessages: appendProtocolMessage(state.chatMessages, action.message),
22
- error: null
28
+ error: null,
29
+ errorInfo: null,
30
+ retryInfo: null
23
31
  };
24
32
  case "Submit": return {
25
33
  ...state,
26
34
  status: "running",
27
35
  error: null,
36
+ errorInfo: null,
37
+ retryInfo: null,
28
38
  seenEventIds: [],
29
39
  chatMessages: appendProtocolMessage(state.chatMessages, action.message),
30
40
  sessionEvents: [...state.sessionEvents, UserMessageSubmitted.make({ message: action.message })]
@@ -33,12 +43,16 @@ const reduceAgentChatState = (state, action) => {
33
43
  ...state,
34
44
  chatMessages: appendProtocolMessage(state.chatMessages, action.message),
35
45
  error: null,
46
+ errorInfo: null,
47
+ retryInfo: null,
36
48
  sessionEvents: [...state.sessionEvents, ProtocolMessageAppended.make({ message: action.message })]
37
49
  };
38
50
  case "SubmitHitlResponse": return {
39
51
  ...state,
40
52
  status: "running",
41
53
  error: null,
54
+ errorInfo: null,
55
+ retryInfo: null,
42
56
  seenEventIds: [],
43
57
  chatMessages: applyAgentEventToChatMessages(state.chatMessages, hitlResponseEvent(action.response))
44
58
  };
@@ -48,6 +62,8 @@ const reduceAgentChatState = (state, action) => {
48
62
  return {
49
63
  ...state,
50
64
  error: null,
65
+ errorInfo: null,
66
+ retryInfo: null,
51
67
  chatMessages: next.messages,
52
68
  sessionEvents: [...state.sessionEvents, TurnDeleted.make({
53
69
  turnStartMessageId: next.turnStartMessageId,
@@ -62,6 +78,8 @@ const reduceAgentChatState = (state, action) => {
62
78
  ...state,
63
79
  status: "running",
64
80
  error: null,
81
+ errorInfo: null,
82
+ retryInfo: null,
65
83
  seenEventIds: [],
66
84
  chatMessages: next.messages,
67
85
  sessionEvents: [...state.sessionEvents, MessagesRegenerated.make({
@@ -77,6 +95,8 @@ const reduceAgentChatState = (state, action) => {
77
95
  ...state,
78
96
  status: "running",
79
97
  error: null,
98
+ errorInfo: null,
99
+ retryInfo: null,
80
100
  seenEventIds: [],
81
101
  chatMessages: next.messages,
82
102
  sessionEvents: [...state.sessionEvents, UserMessageEdited.make({
@@ -93,29 +113,41 @@ const reduceAgentChatState = (state, action) => {
93
113
  ...state,
94
114
  status: "running",
95
115
  error: null,
116
+ errorInfo: null,
117
+ retryInfo: null,
96
118
  chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)
97
119
  }, action.event);
98
120
  case "AgentError": return rememberEvent({
99
121
  ...state,
100
122
  status: "error",
101
123
  error: action.event.message,
124
+ errorInfo: action.event,
125
+ retryInfo: null,
102
126
  chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)
103
127
  }, action.event);
104
128
  case "AgentEnd": return rememberEvent({
105
129
  ...state,
106
130
  status: "done",
107
131
  error: null,
132
+ errorInfo: null,
133
+ retryInfo: null,
108
134
  chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)
109
135
  }, action.event);
110
136
  case "AgentAwaitingInput": return rememberEvent({
111
137
  ...state,
112
138
  status: "waiting",
113
139
  error: null,
140
+ errorInfo: null,
141
+ retryInfo: null,
142
+ chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)
143
+ }, action.event);
144
+ case "AgentRetry": return rememberEvent({
145
+ ...state,
146
+ retryInfo: action.event,
114
147
  chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)
115
148
  }, action.event);
116
- case "AssistantMessage":
117
- case "AgentRetry":
118
149
  case "CompactionEnd":
150
+ case "AssistantMessage":
119
151
  case "CompactionStart":
120
152
  case "LLMReasoningDelta":
121
153
  case "LLMStreamEnd":
@@ -138,21 +170,25 @@ const reduceAgentChatState = (state, action) => {
138
170
  case "ToolInputStart":
139
171
  case "TurnEnd":
140
172
  case "TurnStart":
141
- case "UsageUpdate": return rememberEvent({
173
+ case "UsageUpdate": return rememberEvent(clearRetryInfo({
142
174
  ...state,
143
175
  chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)
144
- }, action.event);
176
+ }), action.event);
145
177
  }
146
178
  case "Error": return {
147
179
  ...state,
148
180
  status: "error",
149
181
  error: action.message,
182
+ errorInfo: null,
183
+ retryInfo: null,
150
184
  chatMessages: markChatError(state.chatMessages, action.message)
151
185
  };
152
186
  case "Abort": return {
153
187
  ...state,
154
188
  status: "aborted",
155
- error: null
189
+ error: null,
190
+ errorInfo: null,
191
+ retryInfo: null
156
192
  };
157
193
  }
158
194
  };
@@ -1 +1 @@
1
- {"version":3,"file":"chat-core.mjs","names":[],"sources":["../../src/react/chat-core.ts"],"sourcesContent":["import {\n hitlResponseEvent,\n type AgentEvent,\n type AgentMessage,\n type Content,\n type HitlResponse,\n type UserMessage\n} from '@yolk-sdk/agent/protocol'\nimport {\n appendProtocolMessage,\n applyAgentEventToChatMessages,\n deleteChatTurn,\n editChatUserMessage,\n markChatError,\n regenerateChatMessagesFrom,\n type AgentChatMessage,\n type AgentChatPart,\n type ApplyAgentEventToChatMessagesOptions\n} from './chat-messages.ts'\nimport {\n MessagesRegenerated,\n ProtocolMessageAppended,\n TurnDeleted,\n UserMessageEdited,\n UserMessageSubmitted,\n type AgentChatSessionEvent\n} from './chat-session-events.ts'\n\nexport type AgentRunStatus = 'idle' | 'running' | 'waiting' | 'done' | 'error' | 'aborted'\n\nexport type AgentChatState = {\n readonly status: AgentRunStatus\n readonly error: string | null\n readonly chatMessages: ReadonlyArray<AgentChatMessage>\n readonly sessionEvents: ReadonlyArray<AgentChatSessionEvent>\n readonly seenEventIds: ReadonlyArray<string>\n}\n\nexport const initialAgentChatState: AgentChatState = {\n status: 'idle',\n error: null,\n chatMessages: [],\n sessionEvents: [],\n seenEventIds: []\n}\n\nconst hasSeenEvent = (state: AgentChatState, event: AgentEvent) =>\n event.eventId !== undefined && state.seenEventIds.includes(event.eventId)\n\nconst rememberEvent = (state: AgentChatState, event: AgentEvent): AgentChatState =>\n event.eventId === undefined\n ? state\n : { ...state, seenEventIds: [...state.seenEventIds, event.eventId] }\n\nexport type AgentChatAction =\n | { readonly _tag: 'HydrateMessage'; readonly message: AgentMessage }\n | { readonly _tag: 'Submit'; readonly message: UserMessage }\n | { readonly _tag: 'AppendMessage'; readonly message: AgentMessage }\n | { readonly _tag: 'SubmitHitlResponse'; readonly response: HitlResponse }\n | { readonly _tag: 'DeleteTurn'; readonly messageId: string }\n | { readonly _tag: 'RegenerateFrom'; readonly messageId: string }\n | { readonly _tag: 'EditUserMessage'; readonly messageId: string; readonly content: Content }\n | ({ readonly _tag: 'Event'; readonly event: AgentEvent } & ApplyAgentEventToChatMessagesOptions)\n | { readonly _tag: 'Error'; readonly message: string }\n | { readonly _tag: 'Abort' }\n\nexport const reduceAgentChatState = (\n state: AgentChatState,\n action: AgentChatAction\n): AgentChatState => {\n switch (action._tag) {\n case 'HydrateMessage':\n return {\n ...state,\n chatMessages: appendProtocolMessage(state.chatMessages, action.message),\n error: null\n }\n case 'Submit':\n return {\n ...state,\n status: 'running',\n error: null,\n seenEventIds: [],\n chatMessages: appendProtocolMessage(state.chatMessages, action.message),\n sessionEvents: [\n ...state.sessionEvents,\n UserMessageSubmitted.make({ message: action.message })\n ]\n }\n case 'AppendMessage':\n return {\n ...state,\n chatMessages: appendProtocolMessage(state.chatMessages, action.message),\n error: null,\n sessionEvents: [\n ...state.sessionEvents,\n ProtocolMessageAppended.make({ message: action.message })\n ]\n }\n case 'SubmitHitlResponse':\n return {\n ...state,\n status: 'running',\n error: null,\n seenEventIds: [],\n chatMessages: applyAgentEventToChatMessages(\n state.chatMessages,\n hitlResponseEvent(action.response)\n )\n }\n case 'DeleteTurn': {\n const next = deleteChatTurn(state.chatMessages, action.messageId)\n\n if (next._tag === 'NotFound') {\n return state\n }\n\n return {\n ...state,\n error: null,\n chatMessages: next.messages,\n sessionEvents: [\n ...state.sessionEvents,\n TurnDeleted.make({\n turnStartMessageId: next.turnStartMessageId,\n deletedMessageIds: next.deletedMessageIds\n })\n ]\n }\n }\n case 'RegenerateFrom': {\n const next = regenerateChatMessagesFrom(state.chatMessages, action.messageId)\n\n if (next._tag === 'NotFound') {\n return state\n }\n\n return {\n ...state,\n status: 'running',\n error: null,\n seenEventIds: [],\n chatMessages: next.messages,\n sessionEvents: [\n ...state.sessionEvents,\n MessagesRegenerated.make({\n fromMessageId: action.messageId,\n keptMessageIds: next.messages.map(message => message.id)\n })\n ]\n }\n }\n case 'EditUserMessage': {\n const next = editChatUserMessage(state.chatMessages, action.messageId, action.content)\n\n if (next._tag !== 'Edited') {\n return state\n }\n\n return {\n ...state,\n status: 'running',\n error: null,\n seenEventIds: [],\n chatMessages: next.messages,\n sessionEvents: [\n ...state.sessionEvents,\n UserMessageEdited.make({\n messageId: next.messageId,\n content: action.content,\n keptMessageIds: next.messages.map(message => message.id)\n })\n ]\n }\n }\n case 'Event': {\n if (hasSeenEvent(state, action.event)) {\n return state\n }\n\n switch (action.event._tag) {\n case 'AgentStart':\n return rememberEvent(\n {\n ...state,\n status: 'running',\n error: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentError':\n return rememberEvent(\n {\n ...state,\n status: 'error',\n error: action.event.message,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentEnd':\n return rememberEvent(\n {\n ...state,\n status: 'done',\n error: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentAwaitingInput':\n return rememberEvent(\n {\n ...state,\n status: 'waiting',\n error: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AssistantMessage':\n case 'AgentRetry':\n case 'CompactionEnd':\n case 'CompactionStart':\n case 'LLMReasoningDelta':\n case 'LLMStreamEnd':\n case 'LLMStreamStart':\n case 'LLMTextDelta':\n case 'ProviderToolResult':\n case 'QuestionAnswered':\n case 'QuestionCancelled':\n case 'QuestionRequested':\n case 'SubagentCompleted':\n case 'SubagentStarted':\n case 'ToolApprovalDenied':\n case 'ToolApprovalGranted':\n case 'ToolApprovalRequested':\n case 'ToolExecutionCompleted':\n case 'ToolExecutionError':\n case 'ToolExecutionStarted':\n case 'ToolInputDelta':\n case 'ToolInputEnd':\n case 'ToolInputStart':\n case 'TurnEnd':\n case 'TurnStart':\n case 'UsageUpdate':\n return rememberEvent(\n {\n ...state,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n }\n }\n case 'Error': {\n return {\n ...state,\n status: 'error',\n error: action.message,\n chatMessages: markChatError(state.chatMessages, action.message)\n }\n }\n case 'Abort':\n return { ...state, status: 'aborted', error: null }\n }\n}\n\nexport const hasAgentMessageReasoning = (message: AgentMessage) =>\n message._tag === 'Assistant' &&\n message.parts.some(part => part._tag === 'Reasoning' && part.text.length > 0)\n\nexport const hasAgentChatReasoningSummary = (state: AgentChatState) =>\n state.chatMessages.some(message =>\n message.parts.some(part => part._tag === 'Reasoning' && part.text.length > 0)\n )\n\nexport const isActiveChatToolPart = (part: AgentChatPart) =>\n part._tag === 'ToolCall' &&\n part.state._tag !== 'Completed' &&\n part.state._tag !== 'ProviderCompleted' &&\n part.state._tag !== 'QuestionAnswered' &&\n part.state._tag !== 'QuestionCancelled' &&\n part.state._tag !== 'Errored' &&\n part.state._tag !== 'Denied'\nexport type ActiveChatToolPart = Extract<AgentChatPart, { readonly _tag: 'ToolCall' }>\n\nexport const isCompletedChatToolPart = (part: AgentChatPart) =>\n part._tag === 'ToolCall' && part.state._tag === 'Completed'\nexport type CompletedChatToolPart = Extract<AgentChatPart, { readonly _tag: 'ToolCall' }>\n\nexport const getActiveChatToolParts = (messages: ReadonlyArray<AgentChatMessage>) =>\n messages.flatMap(message =>\n message.parts.filter((part): part is ActiveChatToolPart => isActiveChatToolPart(part))\n )\n\nexport const getCompletedChatToolParts = (messages: ReadonlyArray<AgentChatMessage>) =>\n messages.flatMap(message =>\n message.parts.filter((part): part is CompletedChatToolPart => isCompletedChatToolPart(part))\n )\n\ntype AgentChatLiveActivityInput = {\n readonly isTextRunning: boolean\n readonly activeToolCallCount: number\n readonly isVoiceActive: boolean\n}\n\nexport const getAgentChatLiveActivityCount = ({\n isTextRunning,\n activeToolCallCount,\n isVoiceActive\n}: AgentChatLiveActivityInput) =>\n (isTextRunning ? 1 : 0) + activeToolCallCount + (isVoiceActive ? 1 : 0)\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-core.mjs","names":[],"sources":["../../src/react/chat-core.ts"],"sourcesContent":["import {\n hitlResponseEvent,\n type AgentError,\n type AgentEvent,\n type AgentMessage,\n type AgentRetry,\n type Content,\n type HitlResponse,\n type UserMessage\n} from '@yolk-sdk/agent/protocol'\nimport {\n appendProtocolMessage,\n applyAgentEventToChatMessages,\n deleteChatTurn,\n editChatUserMessage,\n markChatError,\n regenerateChatMessagesFrom,\n type AgentChatMessage,\n type AgentChatPart,\n type ApplyAgentEventToChatMessagesOptions\n} from './chat-messages.ts'\nimport {\n MessagesRegenerated,\n ProtocolMessageAppended,\n TurnDeleted,\n UserMessageEdited,\n UserMessageSubmitted,\n type AgentChatSessionEvent\n} from './chat-session-events.ts'\n\nexport type AgentRunStatus = 'idle' | 'running' | 'waiting' | 'done' | 'error' | 'aborted'\n\nexport type AgentChatState = {\n readonly status: AgentRunStatus\n readonly error: string | null\n readonly errorInfo: AgentError | null\n readonly retryInfo: AgentRetry | null\n readonly chatMessages: ReadonlyArray<AgentChatMessage>\n readonly sessionEvents: ReadonlyArray<AgentChatSessionEvent>\n readonly seenEventIds: ReadonlyArray<string>\n}\n\nexport const initialAgentChatState: AgentChatState = {\n status: 'idle',\n error: null,\n errorInfo: null,\n retryInfo: null,\n chatMessages: [],\n sessionEvents: [],\n seenEventIds: []\n}\n\nconst hasSeenEvent = (state: AgentChatState, event: AgentEvent) =>\n event.eventId !== undefined && state.seenEventIds.includes(event.eventId)\n\nconst rememberEvent = (state: AgentChatState, event: AgentEvent): AgentChatState =>\n event.eventId === undefined\n ? state\n : { ...state, seenEventIds: [...state.seenEventIds, event.eventId] }\n\nconst clearRetryInfo = (state: AgentChatState): AgentChatState =>\n state.retryInfo === null ? state : { ...state, retryInfo: null }\n\nexport type AgentChatAction =\n | { readonly _tag: 'HydrateMessage'; readonly message: AgentMessage }\n | { readonly _tag: 'Submit'; readonly message: UserMessage }\n | { readonly _tag: 'AppendMessage'; readonly message: AgentMessage }\n | { readonly _tag: 'SubmitHitlResponse'; readonly response: HitlResponse }\n | { readonly _tag: 'DeleteTurn'; readonly messageId: string }\n | { readonly _tag: 'RegenerateFrom'; readonly messageId: string }\n | { readonly _tag: 'EditUserMessage'; readonly messageId: string; readonly content: Content }\n | ({ readonly _tag: 'Event'; readonly event: AgentEvent } & ApplyAgentEventToChatMessagesOptions)\n | { readonly _tag: 'Error'; readonly message: string }\n | { readonly _tag: 'Abort' }\n\nexport const reduceAgentChatState = (\n state: AgentChatState,\n action: AgentChatAction\n): AgentChatState => {\n switch (action._tag) {\n case 'HydrateMessage':\n return {\n ...state,\n chatMessages: appendProtocolMessage(state.chatMessages, action.message),\n error: null,\n errorInfo: null,\n retryInfo: null\n }\n case 'Submit':\n return {\n ...state,\n status: 'running',\n error: null,\n errorInfo: null,\n retryInfo: null,\n seenEventIds: [],\n chatMessages: appendProtocolMessage(state.chatMessages, action.message),\n sessionEvents: [\n ...state.sessionEvents,\n UserMessageSubmitted.make({ message: action.message })\n ]\n }\n case 'AppendMessage':\n return {\n ...state,\n chatMessages: appendProtocolMessage(state.chatMessages, action.message),\n error: null,\n errorInfo: null,\n retryInfo: null,\n sessionEvents: [\n ...state.sessionEvents,\n ProtocolMessageAppended.make({ message: action.message })\n ]\n }\n case 'SubmitHitlResponse':\n return {\n ...state,\n status: 'running',\n error: null,\n errorInfo: null,\n retryInfo: null,\n seenEventIds: [],\n chatMessages: applyAgentEventToChatMessages(\n state.chatMessages,\n hitlResponseEvent(action.response)\n )\n }\n case 'DeleteTurn': {\n const next = deleteChatTurn(state.chatMessages, action.messageId)\n\n if (next._tag === 'NotFound') {\n return state\n }\n\n return {\n ...state,\n error: null,\n errorInfo: null,\n retryInfo: null,\n chatMessages: next.messages,\n sessionEvents: [\n ...state.sessionEvents,\n TurnDeleted.make({\n turnStartMessageId: next.turnStartMessageId,\n deletedMessageIds: next.deletedMessageIds\n })\n ]\n }\n }\n case 'RegenerateFrom': {\n const next = regenerateChatMessagesFrom(state.chatMessages, action.messageId)\n\n if (next._tag === 'NotFound') {\n return state\n }\n\n return {\n ...state,\n status: 'running',\n error: null,\n errorInfo: null,\n retryInfo: null,\n seenEventIds: [],\n chatMessages: next.messages,\n sessionEvents: [\n ...state.sessionEvents,\n MessagesRegenerated.make({\n fromMessageId: action.messageId,\n keptMessageIds: next.messages.map(message => message.id)\n })\n ]\n }\n }\n case 'EditUserMessage': {\n const next = editChatUserMessage(state.chatMessages, action.messageId, action.content)\n\n if (next._tag !== 'Edited') {\n return state\n }\n\n return {\n ...state,\n status: 'running',\n error: null,\n errorInfo: null,\n retryInfo: null,\n seenEventIds: [],\n chatMessages: next.messages,\n sessionEvents: [\n ...state.sessionEvents,\n UserMessageEdited.make({\n messageId: next.messageId,\n content: action.content,\n keptMessageIds: next.messages.map(message => message.id)\n })\n ]\n }\n }\n case 'Event': {\n if (hasSeenEvent(state, action.event)) {\n return state\n }\n\n switch (action.event._tag) {\n case 'AgentStart':\n return rememberEvent(\n {\n ...state,\n status: 'running',\n error: null,\n errorInfo: null,\n retryInfo: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentError':\n return rememberEvent(\n {\n ...state,\n status: 'error',\n error: action.event.message,\n errorInfo: action.event,\n retryInfo: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentEnd':\n return rememberEvent(\n {\n ...state,\n status: 'done',\n error: null,\n errorInfo: null,\n retryInfo: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentAwaitingInput':\n return rememberEvent(\n {\n ...state,\n status: 'waiting',\n error: null,\n errorInfo: null,\n retryInfo: null,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'AgentRetry':\n return rememberEvent(\n {\n ...state,\n retryInfo: action.event,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n },\n action.event\n )\n case 'CompactionEnd':\n case 'AssistantMessage':\n case 'CompactionStart':\n case 'LLMReasoningDelta':\n case 'LLMStreamEnd':\n case 'LLMStreamStart':\n case 'LLMTextDelta':\n case 'ProviderToolResult':\n case 'QuestionAnswered':\n case 'QuestionCancelled':\n case 'QuestionRequested':\n case 'SubagentCompleted':\n case 'SubagentStarted':\n case 'ToolApprovalDenied':\n case 'ToolApprovalGranted':\n case 'ToolApprovalRequested':\n case 'ToolExecutionCompleted':\n case 'ToolExecutionError':\n case 'ToolExecutionStarted':\n case 'ToolInputDelta':\n case 'ToolInputEnd':\n case 'ToolInputStart':\n case 'TurnEnd':\n case 'TurnStart':\n case 'UsageUpdate':\n return rememberEvent(\n clearRetryInfo({\n ...state,\n chatMessages: applyAgentEventToChatMessages(state.chatMessages, action.event, action)\n }),\n action.event\n )\n }\n }\n case 'Error': {\n return {\n ...state,\n status: 'error',\n error: action.message,\n errorInfo: null,\n retryInfo: null,\n chatMessages: markChatError(state.chatMessages, action.message)\n }\n }\n case 'Abort':\n return { ...state, status: 'aborted', error: null, errorInfo: null, retryInfo: null }\n }\n}\n\nexport const hasAgentMessageReasoning = (message: AgentMessage) =>\n message._tag === 'Assistant' &&\n message.parts.some(part => part._tag === 'Reasoning' && part.text.length > 0)\n\nexport const hasAgentChatReasoningSummary = (state: AgentChatState) =>\n state.chatMessages.some(message =>\n message.parts.some(part => part._tag === 'Reasoning' && part.text.length > 0)\n )\n\nexport const isActiveChatToolPart = (part: AgentChatPart) =>\n part._tag === 'ToolCall' &&\n part.state._tag !== 'Completed' &&\n part.state._tag !== 'ProviderCompleted' &&\n part.state._tag !== 'QuestionAnswered' &&\n part.state._tag !== 'QuestionCancelled' &&\n part.state._tag !== 'Errored' &&\n part.state._tag !== 'Denied'\nexport type ActiveChatToolPart = Extract<AgentChatPart, { readonly _tag: 'ToolCall' }>\n\nexport const isCompletedChatToolPart = (part: AgentChatPart) =>\n part._tag === 'ToolCall' && part.state._tag === 'Completed'\nexport type CompletedChatToolPart = Extract<AgentChatPart, { readonly _tag: 'ToolCall' }>\n\nexport const getActiveChatToolParts = (messages: ReadonlyArray<AgentChatMessage>) =>\n messages.flatMap(message =>\n message.parts.filter((part): part is ActiveChatToolPart => isActiveChatToolPart(part))\n )\n\nexport const getCompletedChatToolParts = (messages: ReadonlyArray<AgentChatMessage>) =>\n messages.flatMap(message =>\n message.parts.filter((part): part is CompletedChatToolPart => isCompletedChatToolPart(part))\n )\n\ntype AgentChatLiveActivityInput = {\n readonly isTextRunning: boolean\n readonly activeToolCallCount: number\n readonly isVoiceActive: boolean\n}\n\nexport const getAgentChatLiveActivityCount = ({\n isTextRunning,\n activeToolCallCount,\n isVoiceActive\n}: AgentChatLiveActivityInput) =>\n (isTextRunning ? 1 : 0) + activeToolCallCount + (isVoiceActive ? 1 : 0)\n"],"mappings":";;;;AA0CA,MAAa,wBAAwC;CACnD,QAAQ;CACR,OAAO;CACP,WAAW;CACX,WAAW;CACX,cAAc,CAAC;CACf,eAAe,CAAC;CAChB,cAAc,CAAC;AACjB;AAEA,MAAM,gBAAgB,OAAuB,UAC3C,MAAM,YAAY,KAAA,KAAa,MAAM,aAAa,SAAS,MAAM,OAAO;AAE1E,MAAM,iBAAiB,OAAuB,UAC5C,MAAM,YAAY,KAAA,IACd,QACA;CAAE,GAAG;CAAO,cAAc,CAAC,GAAG,MAAM,cAAc,MAAM,OAAO;AAAE;AAEvE,MAAM,kBAAkB,UACtB,MAAM,cAAc,OAAO,QAAQ;CAAE,GAAG;CAAO,WAAW;AAAK;AAcjE,MAAa,wBACX,OACA,WACmB;CACnB,QAAQ,OAAO,MAAf;EACE,KAAK,kBACH,OAAO;GACL,GAAG;GACH,cAAc,sBAAsB,MAAM,cAAc,OAAO,OAAO;GACtE,OAAO;GACP,WAAW;GACX,WAAW;EACb;EACF,KAAK,UACH,OAAO;GACL,GAAG;GACH,QAAQ;GACR,OAAO;GACP,WAAW;GACX,WAAW;GACX,cAAc,CAAC;GACf,cAAc,sBAAsB,MAAM,cAAc,OAAO,OAAO;GACtE,eAAe,CACb,GAAG,MAAM,eACT,qBAAqB,KAAK,EAAE,SAAS,OAAO,QAAQ,CAAC,CACvD;EACF;EACF,KAAK,iBACH,OAAO;GACL,GAAG;GACH,cAAc,sBAAsB,MAAM,cAAc,OAAO,OAAO;GACtE,OAAO;GACP,WAAW;GACX,WAAW;GACX,eAAe,CACb,GAAG,MAAM,eACT,wBAAwB,KAAK,EAAE,SAAS,OAAO,QAAQ,CAAC,CAC1D;EACF;EACF,KAAK,sBACH,OAAO;GACL,GAAG;GACH,QAAQ;GACR,OAAO;GACP,WAAW;GACX,WAAW;GACX,cAAc,CAAC;GACf,cAAc,8BACZ,MAAM,cACN,kBAAkB,OAAO,QAAQ,CACnC;EACF;EACF,KAAK,cAAc;GACjB,MAAM,OAAO,eAAe,MAAM,cAAc,OAAO,SAAS;GAEhE,IAAI,KAAK,SAAS,YAChB,OAAO;GAGT,OAAO;IACL,GAAG;IACH,OAAO;IACP,WAAW;IACX,WAAW;IACX,cAAc,KAAK;IACnB,eAAe,CACb,GAAG,MAAM,eACT,YAAY,KAAK;KACf,oBAAoB,KAAK;KACzB,mBAAmB,KAAK;IAC1B,CAAC,CACH;GACF;EACF;EACA,KAAK,kBAAkB;GACrB,MAAM,OAAO,2BAA2B,MAAM,cAAc,OAAO,SAAS;GAE5E,IAAI,KAAK,SAAS,YAChB,OAAO;GAGT,OAAO;IACL,GAAG;IACH,QAAQ;IACR,OAAO;IACP,WAAW;IACX,WAAW;IACX,cAAc,CAAC;IACf,cAAc,KAAK;IACnB,eAAe,CACb,GAAG,MAAM,eACT,oBAAoB,KAAK;KACvB,eAAe,OAAO;KACtB,gBAAgB,KAAK,SAAS,KAAI,YAAW,QAAQ,EAAE;IACzD,CAAC,CACH;GACF;EACF;EACA,KAAK,mBAAmB;GACtB,MAAM,OAAO,oBAAoB,MAAM,cAAc,OAAO,WAAW,OAAO,OAAO;GAErF,IAAI,KAAK,SAAS,UAChB,OAAO;GAGT,OAAO;IACL,GAAG;IACH,QAAQ;IACR,OAAO;IACP,WAAW;IACX,WAAW;IACX,cAAc,CAAC;IACf,cAAc,KAAK;IACnB,eAAe,CACb,GAAG,MAAM,eACT,kBAAkB,KAAK;KACrB,WAAW,KAAK;KAChB,SAAS,OAAO;KAChB,gBAAgB,KAAK,SAAS,KAAI,YAAW,QAAQ,EAAE;IACzD,CAAC,CACH;GACF;EACF;EACA,KAAK;GACH,IAAI,aAAa,OAAO,OAAO,KAAK,GAClC,OAAO;GAGT,QAAQ,OAAO,MAAM,MAArB;IACE,KAAK,cACH,OAAO,cACL;KACE,GAAG;KACH,QAAQ;KACR,OAAO;KACP,WAAW;KACX,WAAW;KACX,cAAc,8BAA8B,MAAM,cAAc,OAAO,OAAO,MAAM;IACtF,GACA,OAAO,KACT;IACF,KAAK,cACH,OAAO,cACL;KACE,GAAG;KACH,QAAQ;KACR,OAAO,OAAO,MAAM;KACpB,WAAW,OAAO;KAClB,WAAW;KACX,cAAc,8BAA8B,MAAM,cAAc,OAAO,OAAO,MAAM;IACtF,GACA,OAAO,KACT;IACF,KAAK,YACH,OAAO,cACL;KACE,GAAG;KACH,QAAQ;KACR,OAAO;KACP,WAAW;KACX,WAAW;KACX,cAAc,8BAA8B,MAAM,cAAc,OAAO,OAAO,MAAM;IACtF,GACA,OAAO,KACT;IACF,KAAK,sBACH,OAAO,cACL;KACE,GAAG;KACH,QAAQ;KACR,OAAO;KACP,WAAW;KACX,WAAW;KACX,cAAc,8BAA8B,MAAM,cAAc,OAAO,OAAO,MAAM;IACtF,GACA,OAAO,KACT;IACF,KAAK,cACH,OAAO,cACL;KACE,GAAG;KACH,WAAW,OAAO;KAClB,cAAc,8BAA8B,MAAM,cAAc,OAAO,OAAO,MAAM;IACtF,GACA,OAAO,KACT;IACF,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK,eACH,OAAO,cACL,eAAe;KACb,GAAG;KACH,cAAc,8BAA8B,MAAM,cAAc,OAAO,OAAO,MAAM;IACtF,CAAC,GACD,OAAO,KACT;GACJ;EAEF,KAAK,SACH,OAAO;GACL,GAAG;GACH,QAAQ;GACR,OAAO,OAAO;GACd,WAAW;GACX,WAAW;GACX,cAAc,cAAc,MAAM,cAAc,OAAO,OAAO;EAChE;EAEF,KAAK,SACH,OAAO;GAAE,GAAG;GAAO,QAAQ;GAAW,OAAO;GAAM,WAAW;GAAM,WAAW;EAAK;CACxF;AACF;AAEA,MAAa,4BAA4B,YACvC,QAAQ,SAAS,eACjB,QAAQ,MAAM,MAAK,SAAQ,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,CAAC;AAE9E,MAAa,gCAAgC,UAC3C,MAAM,aAAa,MAAK,YACtB,QAAQ,MAAM,MAAK,SAAQ,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,CAAC,CAC9E;AAEF,MAAa,wBAAwB,SACnC,KAAK,SAAS,cACd,KAAK,MAAM,SAAS,eACpB,KAAK,MAAM,SAAS,uBACpB,KAAK,MAAM,SAAS,sBACpB,KAAK,MAAM,SAAS,uBACpB,KAAK,MAAM,SAAS,aACpB,KAAK,MAAM,SAAS;AAGtB,MAAa,2BAA2B,SACtC,KAAK,SAAS,cAAc,KAAK,MAAM,SAAS;AAGlD,MAAa,0BAA0B,aACrC,SAAS,SAAQ,YACf,QAAQ,MAAM,QAAQ,SAAqC,qBAAqB,IAAI,CAAC,CACvF;AAEF,MAAa,6BAA6B,aACxC,SAAS,SAAQ,YACf,QAAQ,MAAM,QAAQ,SAAwC,wBAAwB,IAAI,CAAC,CAC7F;AAQF,MAAa,iCAAiC,EAC5C,eACA,qBACA,qBAEC,gBAAgB,IAAI,KAAK,uBAAuB,gBAAgB,IAAI"}
@@ -1,5 +1,5 @@
1
1
  import { AgentChatMessage } from "./chat-messages.mjs";
2
- import { Content, QuestionRequest, QuestionResponse, ToolApprovalRequest, ToolCall, ToolResult } from "@yolk-sdk/agent/protocol";
2
+ import { AgentRetry, Content, QuestionRequest, QuestionResponse, ToolApprovalRequest, ToolCall, ToolResult } from "@yolk-sdk/agent/protocol";
3
3
  import { Option } from "effect";
4
4
 
5
5
  //#region src/react/chat-items.d.ts
@@ -104,6 +104,10 @@ type AgentChatItem = {
104
104
  readonly _tag: 'AssistantDraft';
105
105
  readonly id: string;
106
106
  readonly text: string;
107
+ } | {
108
+ readonly _tag: 'Retry';
109
+ readonly id: string;
110
+ readonly retry: AgentRetry;
107
111
  } | {
108
112
  readonly _tag: 'AssistantStatus';
109
113
  readonly id: string;
@@ -117,12 +121,14 @@ type BuildAgentChatItemsInput = {
117
121
  readonly messages: ReadonlyArray<AgentChatMessage>;
118
122
  readonly isRunning: boolean;
119
123
  readonly activeToolLabel: Option.Option<string>;
124
+ readonly retryInfo?: AgentRetry | null;
120
125
  };
121
126
  declare const dedupeAgentChatToolRunItems: (items: ReadonlyArray<AgentChatItem>) => ReadonlyArray<AgentChatItem>;
122
127
  declare const buildAgentChatItems: ({
123
128
  messages,
124
129
  isRunning,
125
- activeToolLabel
130
+ activeToolLabel,
131
+ retryInfo
126
132
  }: BuildAgentChatItemsInput) => ReadonlyArray<AgentChatItem>;
127
133
  //#endregion
128
134
  export { AgentChatItem, BuildAgentChatItemsInput, ToolDuration, ToolRunState, ToolRunTiming, buildAgentChatItems, dedupeAgentChatToolRunItems };
@@ -1 +1 @@
1
- {"version":3,"file":"chat-items.d.mts","names":[],"sources":["../../src/react/chat-items.ts"],"mappings":";;;;;KAYY,YAAA;EAAA,SACG,IAAA;EAAA,SAAwB,YAAA;AAAA;EAAA,SACxB,IAAA;AAAA;AAAA,KAEV,eAAA;EAAA,SACM,QAAA;IAAA,SAAqB,IAAA;EAAA;EAAA,SACrB,WAAA;EAAA,SACA,SAAA;AAAA;AAAA,KAGN,oBAAA;EAAA,SACM,QAAA;IAAA,SAAqB,IAAA;EAAA;EAAA,SACrB,WAAA;EAAA,SACA,SAAA;AAAA;AAAA,KAGN,kBAAA;EAAA,SACM,QAAA;IAAA,SAAqB,IAAA;IAAA,SAAwB,YAAA;EAAA;EAAA,SAC7C,WAAA;EAAA,SACA,SAAA;AAAA;AAAA,KAGC,aAAA,GAAgB,eAAA,GAAkB,oBAAA,GAAuB,kBAAA;AAAA,KAEhE,qBAAA,GAAwB,aAAa;AAAA,KAE9B,YAAA;EAAA,SACI,IAAA;AAAA,IAAoB,oBAAA;EAAA,SACpB,IAAA;AAAA,IAAmB,eAAA;EAAA,SACnB,IAAA;EAAA,SAAiC,KAAA;AAAA,IAAkB,eAAA;EAAA,SAEpD,IAAA;EAAA,SACA,OAAA,GAAU,mBAAA;AAAA,IACjB,eAAA;EAAA,SACQ,IAAA;EAAA,SAAyB,MAAA;AAAA,IAAmB,eAAA;EAAA,SAC5C,IAAA;EAAA,SAAoC,OAAA,EAAS,eAAA;AAAA,IAAoB,eAAA;EAAA,SAElE,IAAA;EAAA,SACA,QAAA,EAAU,gBAAA;EAAA,SACV,OAAA,GAAU,eAAA;AAAA,IACjB,eAAA;EAAA,SAEO,IAAA;EAAA,SACA,QAAA,EAAU,gBAAA;EAAA,SACV,OAAA,GAAU,eAAA;AAAA,IACjB,eAAA;EAAA,SACQ,IAAA;EAAA,SAA4B,MAAA,EAAQ,UAAA;AAAA,IAAe,qBAAA;EAAA,SACnD,IAAA;EAAA,SAA0B,OAAA;AAAA,IAAoB,qBAAA;EAAA,SAE/C,IAAA;EAAA,SACA,MAAA,EAAQ,UAAA;AAAA,IACf,eAAA;AAAA,KAEI,aAAA;EAAA,SAEG,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;EAAA,SACA,OAAA,EAAS,OAAA;AAAA;EAAA,SAGT,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;EAAA,SACA,OAAA,EAAS,OAAA;AAAA;EAAA,SAGT,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA;AAAA;EAAA,SAGA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA,EAAM,QAAA;EAAA,SACN,KAAA,EAAO,YAAA;AAAA;EAAA,SAGP,IAAA;EAAA,SACA,EAAA;EAAA,SACA,SAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA,EAAS,OAAA;EAAA,SACT,OAAA;AAAA;EAAA,SAEA,IAAA;EAAA,SAA4B,EAAA;EAAA,SAAqB,IAAA;AAAA;EAAA,SACjD,IAAA;EAAA,SAAiC,EAAA;EAAA,SAAqB,IAAA;AAAA;EAAA,SACtD,IAAA;EAAA,SAAkC,EAAA;EAAA,SAAqB,KAAA;AAAA;EAAA,SACvD,IAAA;EAAA,SAAwB,EAAA;EAAA,SAAqB,OAAA;AAAA;AAAA,KAEhD,wBAAA;EAAA,SACD,QAAA,EAAU,aAAA,CAAc,gBAAA;EAAA,SACxB,SAAA;EAAA,SACA,eAAA,EAAiB,MAAA,CAAO,MAAA;AAAA;AAAA,cAGtB,2BAAA,GACX,KAAA,EAAO,aAAA,CAAc,aAAA,MACpB,aAAA,CAAc,aAAA;AAAA,cAuMJ,mBAAA;EAAuB,QAAA;EAAA,SAAA;EAAA;AAAA,GAIjC,wBAAA,KAA2B,aAAA,CAAc,aAAA"}
1
+ {"version":3,"file":"chat-items.d.mts","names":[],"sources":["../../src/react/chat-items.ts"],"mappings":"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"}
@@ -153,16 +153,23 @@ const itemFromPart = (message, part) => {
153
153
  });
154
154
  }
155
155
  };
156
- const buildAgentChatItems = ({ messages, isRunning, activeToolLabel }) => {
156
+ const buildAgentChatItems = ({ messages, isRunning, activeToolLabel, retryInfo }) => {
157
157
  const items = dedupeAgentChatToolRunItems(Array.getSomes(Array.flatMap(messages, (message) => Array.map(message.parts, (part) => itemFromPart(message, part)))));
158
- if (isRunning) return [...items, {
159
- _tag: "AssistantStatus",
160
- id: "assistant-status",
161
- label: activeStatusLabel({
162
- messages,
163
- activeToolLabel
164
- })
165
- }];
158
+ if (isRunning) {
159
+ if (retryInfo !== void 0 && retryInfo !== null) return [...items, {
160
+ _tag: "Retry",
161
+ id: "agent-retry",
162
+ retry: retryInfo
163
+ }];
164
+ return [...items, {
165
+ _tag: "AssistantStatus",
166
+ id: "assistant-status",
167
+ label: activeStatusLabel({
168
+ messages,
169
+ activeToolLabel
170
+ })
171
+ }];
172
+ }
166
173
  return items;
167
174
  };
168
175
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"chat-items.mjs","names":["Arr"],"sources":["../../src/react/chat-items.ts"],"sourcesContent":["import { Array as Arr, Option } from 'effect'\nimport {\n contentText,\n type QuestionRequest,\n type QuestionResponse,\n type ToolApprovalRequest,\n type ToolResult,\n type Content,\n type ToolCall\n} from '@yolk-sdk/agent/protocol'\nimport type { AgentChatMessage, ChatToolState } from './chat-messages.ts'\n\nexport type ToolDuration =\n | { readonly _tag: 'Known'; readonly milliseconds: number }\n | { readonly _tag: 'Unknown' }\n\ntype ToolRunNoTiming = {\n readonly duration: { readonly _tag: 'Unknown' }\n readonly startedAtMs?: undefined\n readonly endedAtMs?: undefined\n}\n\ntype ToolRunStartedTiming = {\n readonly duration: { readonly _tag: 'Unknown' }\n readonly startedAtMs: number\n readonly endedAtMs?: undefined\n}\n\ntype ToolRunKnownTiming = {\n readonly duration: { readonly _tag: 'Known'; readonly milliseconds: number }\n readonly startedAtMs: number\n readonly endedAtMs: number\n}\n\nexport type ToolRunTiming = ToolRunNoTiming | ToolRunStartedTiming | ToolRunKnownTiming\n\ntype ToolRunTerminalTiming = ToolRunTiming\n\nexport type ToolRunState =\n | ({ readonly _tag: 'Running' } & ToolRunStartedTiming)\n | ({ readonly _tag: 'Called' } & ToolRunNoTiming)\n | ({ readonly _tag: 'InputStreaming'; readonly input: string } & ToolRunNoTiming)\n | ({\n readonly _tag: 'ApprovalRequested'\n readonly request?: ToolApprovalRequest\n } & ToolRunNoTiming)\n | ({ readonly _tag: 'Denied'; readonly reason: string } & ToolRunNoTiming)\n | ({ readonly _tag: 'QuestionRequested'; readonly request: QuestionRequest } & ToolRunNoTiming)\n | ({\n readonly _tag: 'QuestionAnswered'\n readonly response: QuestionResponse\n readonly request?: QuestionRequest\n } & ToolRunNoTiming)\n | ({\n readonly _tag: 'QuestionCancelled'\n readonly response: QuestionResponse\n readonly request?: QuestionRequest\n } & ToolRunNoTiming)\n | ({ readonly _tag: 'Completed'; readonly result: ToolResult } & ToolRunTerminalTiming)\n | ({ readonly _tag: 'Errored'; readonly message: string } & ToolRunTerminalTiming)\n | ({\n readonly _tag: 'ProviderCompleted'\n readonly result: ToolResult\n } & ToolRunNoTiming)\n\nexport type AgentChatItem =\n | {\n readonly _tag: 'UserMessage'\n readonly id: string\n readonly messageId: string\n readonly content: Content\n }\n | {\n readonly _tag: 'AssistantMessage'\n readonly id: string\n readonly messageId: string\n readonly content: Content\n }\n | {\n readonly _tag: 'Reasoning'\n readonly id: string\n readonly messageId: string\n readonly text: string\n }\n | {\n readonly _tag: 'ToolRun'\n readonly id: string\n readonly messageId: string\n readonly call: ToolCall\n readonly state: ToolRunState\n }\n | {\n readonly _tag: 'ToolResult'\n readonly id: string\n readonly messageId: string\n readonly toolCallId: string\n readonly name: string\n readonly content: Content\n readonly isError?: boolean\n }\n | { readonly _tag: 'UserDraft'; readonly id: string; readonly text: string }\n | { readonly _tag: 'AssistantDraft'; readonly id: string; readonly text: string }\n | { readonly _tag: 'AssistantStatus'; readonly id: string; readonly label: string }\n | { readonly _tag: 'Error'; readonly id: string; readonly message: string }\n\nexport type BuildAgentChatItemsInput = {\n readonly messages: ReadonlyArray<AgentChatMessage>\n readonly isRunning: boolean\n readonly activeToolLabel: Option.Option<string>\n}\n\nexport const dedupeAgentChatToolRunItems = (\n items: ReadonlyArray<AgentChatItem>\n): ReadonlyArray<AgentChatItem> => {\n // Tool call ids are transcript-global; latest wins when live and persisted projections overlap.\n const latestIndexByToolCallId = new Map<string, number>()\n\n for (const [index, item] of items.entries()) {\n if (item._tag === 'ToolRun') {\n latestIndexByToolCallId.set(item.call.id, index)\n }\n }\n\n return items.filter(\n (item, index) =>\n item._tag !== 'ToolRun' || latestIndexByToolCallId.get(item.call.id) === index\n )\n}\n\nconst activeStatusLabel = ({\n messages,\n activeToolLabel\n}: Pick<BuildAgentChatItemsInput, 'messages' | 'activeToolLabel'>) => {\n if (Option.isSome(activeToolLabel)) {\n return activeToolLabel.value\n }\n\n const parts = messages.flatMap(message =>\n message.parts.map(part => ({ messageRole: message.role, part }))\n )\n\n if (\n parts.some(\n ({ messageRole, part }) =>\n part._tag === 'Text' && part.state === 'streaming' && messageRole === 'assistant'\n )\n ) {\n return 'Responding'\n }\n\n if (parts.some(({ part }) => part._tag === 'Reasoning' && part.state === 'streaming')) {\n return 'Thinking'\n }\n\n return 'Thinking'\n}\n\nconst noTiming = (): ToolRunNoTiming => ({ duration: { _tag: 'Unknown' } })\n\nconst startedTiming = (startedAtMs: number): ToolRunStartedTiming => ({\n duration: { _tag: 'Unknown' },\n startedAtMs\n})\n\nconst unknownTerminalTiming = (startedAtMs?: number): ToolRunNoTiming | ToolRunStartedTiming =>\n startedAtMs === undefined ? noTiming() : startedTiming(startedAtMs)\n\nconst knownTiming = (startedAtMs: number, endedAtMs: number): ToolRunTiming => ({\n duration: { _tag: 'Known', milliseconds: Math.max(0, endedAtMs - startedAtMs) },\n startedAtMs,\n endedAtMs\n})\n\nconst terminalTimingFromState = (\n state: Extract<ChatToolState, { readonly _tag: 'Completed' | 'Errored' }>\n): ToolRunTerminalTiming => {\n if (state.startedAtMs !== undefined && state.endedAtMs !== undefined) {\n return knownTiming(state.startedAtMs, state.endedAtMs)\n }\n\n return unknownTerminalTiming(state.startedAtMs)\n}\n\nconst toolRunStateFor = (state: ChatToolState): ToolRunState => {\n if (state._tag === 'Running') {\n return { _tag: 'Running', ...startedTiming(state.startedAtMs) }\n }\n\n if (state._tag === 'Completed') {\n return { _tag: 'Completed', ...terminalTimingFromState(state), result: state.result }\n }\n\n if (state._tag === 'InputStreaming') {\n return { _tag: 'InputStreaming', ...noTiming(), input: state.input }\n }\n\n if (state._tag === 'ApprovalRequested') {\n return { _tag: 'ApprovalRequested', ...noTiming(), request: state.request }\n }\n\n if (state._tag === 'Denied') {\n return { _tag: 'Denied', ...noTiming(), reason: state.reason }\n }\n\n if (state._tag === 'QuestionRequested') {\n return { _tag: 'QuestionRequested', ...noTiming(), request: state.request }\n }\n\n if (state._tag === 'QuestionAnswered') {\n return {\n _tag: 'QuestionAnswered',\n ...noTiming(),\n response: state.response,\n request: state.request\n }\n }\n\n if (state._tag === 'QuestionCancelled') {\n return {\n _tag: 'QuestionCancelled',\n ...noTiming(),\n response: state.response,\n request: state.request\n }\n }\n\n if (state._tag === 'Errored') {\n return { _tag: 'Errored', ...terminalTimingFromState(state), message: state.message }\n }\n\n if (state._tag === 'ProviderCompleted') {\n return { _tag: 'ProviderCompleted', ...noTiming(), result: state.result }\n }\n\n return { _tag: 'Called', ...noTiming() }\n}\n\nconst textItemFromPart = (\n message: AgentChatMessage,\n part: Extract<AgentChatMessage['parts'][number], { readonly _tag: 'Text' }>\n): Option.Option<AgentChatItem> => {\n if (part.state === 'streaming') {\n switch (message.role) {\n case 'user':\n return Option.some({\n _tag: 'UserDraft',\n id: part.id,\n text: contentText(part.content)\n })\n case 'assistant':\n return Option.some({\n _tag: 'AssistantDraft',\n id: part.id,\n text: contentText(part.content)\n })\n case 'system':\n return Option.none()\n }\n }\n\n switch (message.role) {\n case 'user':\n return Option.some({\n _tag: 'UserMessage',\n id: part.id,\n messageId: message.id,\n content: part.content\n })\n case 'assistant':\n return Option.some({\n _tag: 'AssistantMessage',\n id: part.id,\n messageId: message.id,\n content: part.content\n })\n case 'system':\n return Option.none()\n }\n}\n\nconst itemFromPart = (\n message: AgentChatMessage,\n part: AgentChatMessage['parts'][number]\n): Option.Option<AgentChatItem> => {\n switch (part._tag) {\n case 'Text':\n return textItemFromPart(message, part)\n case 'Reasoning':\n return Option.some({ _tag: 'Reasoning', id: part.id, messageId: message.id, text: part.text })\n case 'ToolCall':\n return Option.some({\n _tag: 'ToolRun',\n id: part.id,\n messageId: message.id,\n call: part.call,\n state: toolRunStateFor(part.state)\n })\n case 'ToolResult':\n return Option.some({\n _tag: 'ToolResult',\n id: part.id,\n messageId: message.id,\n toolCallId: part.toolCallId,\n name: part.name,\n content: part.content,\n isError: part.isError\n })\n case 'Error':\n return Option.some({ _tag: 'Error', id: part.id, message: part.message })\n }\n}\n\nexport const buildAgentChatItems = ({\n messages,\n isRunning,\n activeToolLabel\n}: BuildAgentChatItemsInput): ReadonlyArray<AgentChatItem> => {\n const items = dedupeAgentChatToolRunItems(\n Arr.getSomes(\n Arr.flatMap(messages, message => Arr.map(message.parts, part => itemFromPart(message, part)))\n )\n )\n\n if (isRunning) {\n return [\n ...items,\n {\n _tag: 'AssistantStatus',\n id: 'assistant-status',\n label: activeStatusLabel({ messages, activeToolLabel })\n }\n ]\n }\n\n return items\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-items.mjs","names":["Arr"],"sources":["../../src/react/chat-items.ts"],"sourcesContent":["import { Array as Arr, Option } from 'effect'\nimport {\n contentText,\n type AgentRetry,\n type QuestionRequest,\n type QuestionResponse,\n type ToolApprovalRequest,\n type ToolResult,\n type Content,\n type ToolCall\n} from '@yolk-sdk/agent/protocol'\nimport type { AgentChatMessage, ChatToolState } from './chat-messages.ts'\n\nexport type ToolDuration =\n | { readonly _tag: 'Known'; readonly milliseconds: number }\n | { readonly _tag: 'Unknown' }\n\ntype ToolRunNoTiming = {\n readonly duration: { readonly _tag: 'Unknown' }\n readonly startedAtMs?: undefined\n readonly endedAtMs?: undefined\n}\n\ntype ToolRunStartedTiming = {\n readonly duration: { readonly _tag: 'Unknown' }\n readonly startedAtMs: number\n readonly endedAtMs?: undefined\n}\n\ntype ToolRunKnownTiming = {\n readonly duration: { readonly _tag: 'Known'; readonly milliseconds: number }\n readonly startedAtMs: number\n readonly endedAtMs: number\n}\n\nexport type ToolRunTiming = ToolRunNoTiming | ToolRunStartedTiming | ToolRunKnownTiming\n\ntype ToolRunTerminalTiming = ToolRunTiming\n\nexport type ToolRunState =\n | ({ readonly _tag: 'Running' } & ToolRunStartedTiming)\n | ({ readonly _tag: 'Called' } & ToolRunNoTiming)\n | ({ readonly _tag: 'InputStreaming'; readonly input: string } & ToolRunNoTiming)\n | ({\n readonly _tag: 'ApprovalRequested'\n readonly request?: ToolApprovalRequest\n } & ToolRunNoTiming)\n | ({ readonly _tag: 'Denied'; readonly reason: string } & ToolRunNoTiming)\n | ({ readonly _tag: 'QuestionRequested'; readonly request: QuestionRequest } & ToolRunNoTiming)\n | ({\n readonly _tag: 'QuestionAnswered'\n readonly response: QuestionResponse\n readonly request?: QuestionRequest\n } & ToolRunNoTiming)\n | ({\n readonly _tag: 'QuestionCancelled'\n readonly response: QuestionResponse\n readonly request?: QuestionRequest\n } & ToolRunNoTiming)\n | ({ readonly _tag: 'Completed'; readonly result: ToolResult } & ToolRunTerminalTiming)\n | ({ readonly _tag: 'Errored'; readonly message: string } & ToolRunTerminalTiming)\n | ({\n readonly _tag: 'ProviderCompleted'\n readonly result: ToolResult\n } & ToolRunNoTiming)\n\nexport type AgentChatItem =\n | {\n readonly _tag: 'UserMessage'\n readonly id: string\n readonly messageId: string\n readonly content: Content\n }\n | {\n readonly _tag: 'AssistantMessage'\n readonly id: string\n readonly messageId: string\n readonly content: Content\n }\n | {\n readonly _tag: 'Reasoning'\n readonly id: string\n readonly messageId: string\n readonly text: string\n }\n | {\n readonly _tag: 'ToolRun'\n readonly id: string\n readonly messageId: string\n readonly call: ToolCall\n readonly state: ToolRunState\n }\n | {\n readonly _tag: 'ToolResult'\n readonly id: string\n readonly messageId: string\n readonly toolCallId: string\n readonly name: string\n readonly content: Content\n readonly isError?: boolean\n }\n | { readonly _tag: 'UserDraft'; readonly id: string; readonly text: string }\n | { readonly _tag: 'AssistantDraft'; readonly id: string; readonly text: string }\n | { readonly _tag: 'Retry'; readonly id: string; readonly retry: AgentRetry }\n | { readonly _tag: 'AssistantStatus'; readonly id: string; readonly label: string }\n | { readonly _tag: 'Error'; readonly id: string; readonly message: string }\n\nexport type BuildAgentChatItemsInput = {\n readonly messages: ReadonlyArray<AgentChatMessage>\n readonly isRunning: boolean\n readonly activeToolLabel: Option.Option<string>\n readonly retryInfo?: AgentRetry | null\n}\n\nexport const dedupeAgentChatToolRunItems = (\n items: ReadonlyArray<AgentChatItem>\n): ReadonlyArray<AgentChatItem> => {\n // Tool call ids are transcript-global; latest wins when live and persisted projections overlap.\n const latestIndexByToolCallId = new Map<string, number>()\n\n for (const [index, item] of items.entries()) {\n if (item._tag === 'ToolRun') {\n latestIndexByToolCallId.set(item.call.id, index)\n }\n }\n\n return items.filter(\n (item, index) => item._tag !== 'ToolRun' || latestIndexByToolCallId.get(item.call.id) === index\n )\n}\n\nconst activeStatusLabel = ({\n messages,\n activeToolLabel\n}: Pick<BuildAgentChatItemsInput, 'messages' | 'activeToolLabel'>) => {\n if (Option.isSome(activeToolLabel)) {\n return activeToolLabel.value\n }\n\n const parts = messages.flatMap(message =>\n message.parts.map(part => ({ messageRole: message.role, part }))\n )\n\n if (\n parts.some(\n ({ messageRole, part }) =>\n part._tag === 'Text' && part.state === 'streaming' && messageRole === 'assistant'\n )\n ) {\n return 'Responding'\n }\n\n if (parts.some(({ part }) => part._tag === 'Reasoning' && part.state === 'streaming')) {\n return 'Thinking'\n }\n\n return 'Thinking'\n}\n\nconst noTiming = (): ToolRunNoTiming => ({ duration: { _tag: 'Unknown' } })\n\nconst startedTiming = (startedAtMs: number): ToolRunStartedTiming => ({\n duration: { _tag: 'Unknown' },\n startedAtMs\n})\n\nconst unknownTerminalTiming = (startedAtMs?: number): ToolRunNoTiming | ToolRunStartedTiming =>\n startedAtMs === undefined ? noTiming() : startedTiming(startedAtMs)\n\nconst knownTiming = (startedAtMs: number, endedAtMs: number): ToolRunTiming => ({\n duration: { _tag: 'Known', milliseconds: Math.max(0, endedAtMs - startedAtMs) },\n startedAtMs,\n endedAtMs\n})\n\nconst terminalTimingFromState = (\n state: Extract<ChatToolState, { readonly _tag: 'Completed' | 'Errored' }>\n): ToolRunTerminalTiming => {\n if (state.startedAtMs !== undefined && state.endedAtMs !== undefined) {\n return knownTiming(state.startedAtMs, state.endedAtMs)\n }\n\n return unknownTerminalTiming(state.startedAtMs)\n}\n\nconst toolRunStateFor = (state: ChatToolState): ToolRunState => {\n if (state._tag === 'Running') {\n return { _tag: 'Running', ...startedTiming(state.startedAtMs) }\n }\n\n if (state._tag === 'Completed') {\n return { _tag: 'Completed', ...terminalTimingFromState(state), result: state.result }\n }\n\n if (state._tag === 'InputStreaming') {\n return { _tag: 'InputStreaming', ...noTiming(), input: state.input }\n }\n\n if (state._tag === 'ApprovalRequested') {\n return { _tag: 'ApprovalRequested', ...noTiming(), request: state.request }\n }\n\n if (state._tag === 'Denied') {\n return { _tag: 'Denied', ...noTiming(), reason: state.reason }\n }\n\n if (state._tag === 'QuestionRequested') {\n return { _tag: 'QuestionRequested', ...noTiming(), request: state.request }\n }\n\n if (state._tag === 'QuestionAnswered') {\n return {\n _tag: 'QuestionAnswered',\n ...noTiming(),\n response: state.response,\n request: state.request\n }\n }\n\n if (state._tag === 'QuestionCancelled') {\n return {\n _tag: 'QuestionCancelled',\n ...noTiming(),\n response: state.response,\n request: state.request\n }\n }\n\n if (state._tag === 'Errored') {\n return { _tag: 'Errored', ...terminalTimingFromState(state), message: state.message }\n }\n\n if (state._tag === 'ProviderCompleted') {\n return { _tag: 'ProviderCompleted', ...noTiming(), result: state.result }\n }\n\n return { _tag: 'Called', ...noTiming() }\n}\n\nconst textItemFromPart = (\n message: AgentChatMessage,\n part: Extract<AgentChatMessage['parts'][number], { readonly _tag: 'Text' }>\n): Option.Option<AgentChatItem> => {\n if (part.state === 'streaming') {\n switch (message.role) {\n case 'user':\n return Option.some({\n _tag: 'UserDraft',\n id: part.id,\n text: contentText(part.content)\n })\n case 'assistant':\n return Option.some({\n _tag: 'AssistantDraft',\n id: part.id,\n text: contentText(part.content)\n })\n case 'system':\n return Option.none()\n }\n }\n\n switch (message.role) {\n case 'user':\n return Option.some({\n _tag: 'UserMessage',\n id: part.id,\n messageId: message.id,\n content: part.content\n })\n case 'assistant':\n return Option.some({\n _tag: 'AssistantMessage',\n id: part.id,\n messageId: message.id,\n content: part.content\n })\n case 'system':\n return Option.none()\n }\n}\n\nconst itemFromPart = (\n message: AgentChatMessage,\n part: AgentChatMessage['parts'][number]\n): Option.Option<AgentChatItem> => {\n switch (part._tag) {\n case 'Text':\n return textItemFromPart(message, part)\n case 'Reasoning':\n return Option.some({ _tag: 'Reasoning', id: part.id, messageId: message.id, text: part.text })\n case 'ToolCall':\n return Option.some({\n _tag: 'ToolRun',\n id: part.id,\n messageId: message.id,\n call: part.call,\n state: toolRunStateFor(part.state)\n })\n case 'ToolResult':\n return Option.some({\n _tag: 'ToolResult',\n id: part.id,\n messageId: message.id,\n toolCallId: part.toolCallId,\n name: part.name,\n content: part.content,\n isError: part.isError\n })\n case 'Error':\n return Option.some({ _tag: 'Error', id: part.id, message: part.message })\n }\n}\n\nexport const buildAgentChatItems = ({\n messages,\n isRunning,\n activeToolLabel,\n retryInfo\n}: BuildAgentChatItemsInput): ReadonlyArray<AgentChatItem> => {\n const items = dedupeAgentChatToolRunItems(\n Arr.getSomes(\n Arr.flatMap(messages, message => Arr.map(message.parts, part => itemFromPart(message, part)))\n )\n )\n\n if (isRunning) {\n if (retryInfo !== undefined && retryInfo !== null) {\n return [...items, { _tag: 'Retry', id: 'agent-retry', retry: retryInfo }]\n }\n\n return [\n ...items,\n {\n _tag: 'AssistantStatus',\n id: 'assistant-status',\n label: activeStatusLabel({ messages, activeToolLabel })\n }\n ]\n }\n\n return items\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/agent",
3
- "version": "0.1.0-canary.20",
3
+ "version": "0.1.0-canary.21",
4
4
  "description": "Protocol, loop, runtime, client, compaction, tools, React, providers, OAuth, skillset, and voice primitives for building Yolk agents.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,8 @@
1
1
  import {
2
+ type AgentError,
2
3
  type AgentEvent,
3
4
  type AgentMessage,
5
+ type AgentRetry,
4
6
  type HitlRequest,
5
7
  type QuestionRequest,
6
8
  type QuestionResponse,
@@ -63,6 +65,8 @@ export type AgentClientState = {
63
65
  readonly reasoning: string
64
66
  readonly toolRuns: ReadonlyArray<AgentToolRun>
65
67
  readonly error: string | null
68
+ readonly errorInfo: AgentError | null
69
+ readonly retryInfo: AgentRetry | null
66
70
  readonly seenEventIds: ReadonlyArray<string>
67
71
  }
68
72
 
@@ -80,9 +84,14 @@ export const initialAgentClientState: AgentClientState = {
80
84
  reasoning: '',
81
85
  toolRuns: [],
82
86
  error: null,
87
+ errorInfo: null,
88
+ retryInfo: null,
83
89
  seenEventIds: []
84
90
  }
85
91
 
92
+ const clearRetryInfo = (state: AgentClientState): AgentClientState =>
93
+ state.retryInfo === null ? state : { ...state, retryInfo: null }
94
+
86
95
  const hasSeenEvent = (state: AgentClientState, event: AgentEvent) =>
87
96
  event.eventId !== undefined && state.seenEventIds.includes(event.eventId)
88
97
 
@@ -260,16 +269,18 @@ const applyAgentEventUnchecked = (
260
269
  reasoning: '',
261
270
  liveMessages: [],
262
271
  toolRuns: completedToolRuns(state.toolRuns),
263
- error: null
272
+ error: null,
273
+ errorInfo: null,
274
+ retryInfo: null
264
275
  }
265
276
  case 'AgentError':
266
- return markAgentError(state, event.message)
277
+ return markAgentError(state, event.message, event)
267
278
  case 'LLMTextDelta':
268
- return { ...state, text: `${state.text}${event.text}` }
279
+ return clearRetryInfo({ ...state, text: `${state.text}${event.text}` })
269
280
  case 'LLMReasoningDelta':
270
- return { ...state, reasoning: `${state.reasoning}${event.text}` }
281
+ return clearRetryInfo({ ...state, reasoning: `${state.reasoning}${event.text}` })
271
282
  case 'ToolInputStart':
272
- return {
283
+ return clearRetryInfo({
273
284
  ...state,
274
285
  toolRuns: replaceToolRun(state.toolRuns, {
275
286
  _tag: 'InputStreaming',
@@ -277,14 +288,17 @@ const applyAgentEventUnchecked = (
277
288
  name: event.name,
278
289
  input: ''
279
290
  })
280
- }
291
+ })
281
292
  case 'ToolInputDelta':
282
- return { ...state, toolRuns: appendToolInputDelta(state.toolRuns, event.id, event.delta) }
293
+ return clearRetryInfo({
294
+ ...state,
295
+ toolRuns: appendToolInputDelta(state.toolRuns, event.id, event.delta)
296
+ })
283
297
  case 'ToolInputEnd':
284
- return {
298
+ return clearRetryInfo({
285
299
  ...state,
286
300
  toolRuns: replaceToolRun(state.toolRuns, { _tag: 'InputReady', call: event.call })
287
- }
301
+ })
288
302
  case 'ToolApprovalRequested':
289
303
  return {
290
304
  ...state,
@@ -370,21 +384,21 @@ const applyAgentEventUnchecked = (
370
384
  })
371
385
  }
372
386
  case 'ProviderToolResult':
373
- return {
387
+ return clearRetryInfo({
374
388
  ...state,
375
389
  toolRuns: replaceToolRun(state.toolRuns, {
376
390
  _tag: 'ProviderCompleted',
377
391
  call: event.call,
378
392
  result: event.result
379
393
  })
380
- }
394
+ })
381
395
  case 'AssistantMessage':
382
- return {
396
+ return clearRetryInfo({
383
397
  ...state,
384
398
  liveMessages: [...state.liveMessages, event.message],
385
399
  text: '',
386
400
  reasoning: ''
387
- }
401
+ })
388
402
  case 'AgentEnd':
389
403
  return {
390
404
  ...state,
@@ -393,7 +407,8 @@ const applyAgentEventUnchecked = (
393
407
  liveMessages: [],
394
408
  text: '',
395
409
  reasoning: '',
396
- toolRuns: completedToolRuns(state.toolRuns)
410
+ toolRuns: completedToolRuns(state.toolRuns),
411
+ retryInfo: null
397
412
  }
398
413
  case 'AgentAwaitingInput':
399
414
  return {
@@ -403,9 +418,12 @@ const applyAgentEventUnchecked = (
403
418
  liveMessages: [],
404
419
  text: '',
405
420
  reasoning: '',
406
- error: null
421
+ error: null,
422
+ errorInfo: null,
423
+ retryInfo: null
407
424
  }
408
425
  case 'AgentRetry':
426
+ return { ...state, retryInfo: event }
409
427
  case 'CompactionEnd':
410
428
  case 'CompactionStart':
411
429
  case 'LLMStreamEnd':
@@ -431,24 +449,31 @@ export const submitAgentUserMessage = (
431
449
  reasoning: '',
432
450
  toolRuns: completedToolRuns(state.toolRuns),
433
451
  error: null,
452
+ errorInfo: null,
453
+ retryInfo: null,
434
454
  seenEventIds: []
435
455
  })
436
456
 
437
457
  export const markAgentError = (
438
458
  state: AgentClientState,
439
- message = 'Agent request failed'
459
+ message = 'Agent request failed',
460
+ errorInfo: AgentError | null = null
440
461
  ): AgentClientState => ({
441
462
  ...state,
442
463
  status: 'error',
443
464
  toolRuns: completedToolRuns(state.toolRuns),
444
- error: message
465
+ error: message,
466
+ errorInfo,
467
+ retryInfo: null
445
468
  })
446
469
 
447
470
  export const markAgentAborted = (state: AgentClientState): AgentClientState => ({
448
471
  ...state,
449
472
  status: 'aborted',
450
473
  toolRuns: completedToolRuns(state.toolRuns),
451
- error: null
474
+ error: null,
475
+ errorInfo: null,
476
+ retryInfo: null
452
477
  })
453
478
 
454
479
  export const reduceAgentEvents = (
package/src/loop/error.ts CHANGED
@@ -1,16 +1,18 @@
1
1
  import * as Schema from 'effect/Schema'
2
- import { AgentError, type AgentErrorCode } from '@yolk-sdk/agent/protocol'
2
+ import { AgentError, ProviderErrorInfo, type AgentErrorCode } from '@yolk-sdk/agent/protocol'
3
3
 
4
4
  export class LLMError extends Schema.TaggedErrorClass<LLMError>()('LLMError', {
5
5
  cause: Schema.Literals([
6
6
  'validation_error',
7
7
  'provider_error',
8
8
  'rate_limit',
9
+ 'overloaded',
9
10
  'context_overflow',
10
11
  'invalid_response'
11
12
  ]),
12
13
  message: Schema.String,
13
- retryable: Schema.Boolean
14
+ retryable: Schema.Boolean,
15
+ provider: Schema.optional(ProviderErrorInfo)
14
16
  }) {}
15
17
 
16
18
  export class FauxExhaustedError extends Schema.TaggedErrorClass<FauxExhaustedError>()(
@@ -75,7 +77,8 @@ export const agentLoopErrorToAgentError = (error: AgentLoopError): AgentError =>
75
77
  return AgentError.make({
76
78
  code: error.cause,
77
79
  message: error.message,
78
- retryable: error.retryable
80
+ retryable: error.retryable,
81
+ ...(error.provider === undefined ? {} : { provider: error.provider })
79
82
  })
80
83
  case 'ToolError':
81
84
  return AgentError.make({
package/src/loop/run.ts CHANGED
@@ -292,8 +292,30 @@ type TurnStreamInput = {
292
292
  readonly turn: number
293
293
  }
294
294
 
295
- const retryDelayMs = (baseDelayMs: number, attempt: number) =>
296
- Math.max(0, Math.floor(baseDelayMs * 2 ** Math.max(0, attempt - 1)))
295
+ const maxUnhintedRetryDelayMs = 30_000
296
+ const maxHintedRetryDelayMs = 2_147_483_647
297
+
298
+ const validDelayMs = (delayMs: number) =>
299
+ Number.isFinite(delayMs) && delayMs >= 0 ? Math.floor(delayMs) : undefined
300
+
301
+ const hintedRetryDelayMs = (error: LLMError) => {
302
+ const delayMs = error.provider?.retryAfterMs
303
+ const validDelay = delayMs === undefined ? undefined : validDelayMs(delayMs)
304
+
305
+ return validDelay === undefined ? undefined : Math.min(validDelay, maxHintedRetryDelayMs)
306
+ }
307
+
308
+ const retryDelayMs = (baseDelayMs: number, attempt: number, error: LLMError) => {
309
+ const hintedDelay = hintedRetryDelayMs(error)
310
+
311
+ if (hintedDelay !== undefined) {
312
+ return hintedDelay
313
+ }
314
+
315
+ const delayMs = validDelayMs(baseDelayMs * 2 ** Math.max(0, attempt - 1)) ?? 0
316
+
317
+ return Math.min(delayMs, maxUnhintedRetryDelayMs)
318
+ }
297
319
 
298
320
  const retryReason = (error: LLMError): AgentErrorCode => error.cause
299
321
 
@@ -332,13 +354,14 @@ const withProviderRetries = (
332
354
  return failAgentLoopError(error)
333
355
  }
334
356
 
335
- const delayMs = retryDelayMs(loopConfig.retryBaseDelayMs, attempt)
357
+ const delayMs = retryDelayMs(loopConfig.retryBaseDelayMs, attempt, error)
336
358
  return Stream.make(
337
359
  AgentRetry.make({
338
360
  attempt,
339
361
  reason: retryReason(error),
340
362
  delayMs,
341
- message: error.message
363
+ message: error.message,
364
+ ...(error.provider === undefined ? {} : { provider: error.provider })
342
365
  })
343
366
  ).pipe(
344
367
  Stream.concat(sleepStream(delayMs)),
@@ -14,7 +14,7 @@ export class LoopConfig extends Context.Service<LoopConfig, LoopConfigShape>()(
14
14
  static defaultLayer = this.layer({
15
15
  maxTurns: 500,
16
16
  maxRetries: 2,
17
- retryBaseDelayMs: 1000,
17
+ retryBaseDelayMs: 2000,
18
18
  toolConcurrency: 4
19
19
  })
20
20
  }