@yolk-sdk/agent 0.0.1-canary.0

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 (161) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/client/index.d.mts +3 -0
  4. package/dist/client/index.mjs +3 -0
  5. package/dist/client/state.d.mts +99 -0
  6. package/dist/client/state.d.mts.map +1 -0
  7. package/dist/client/state.mjs +245 -0
  8. package/dist/client/state.mjs.map +1 -0
  9. package/dist/client/transport.d.mts +67 -0
  10. package/dist/client/transport.d.mts.map +1 -0
  11. package/dist/client/transport.mjs +219 -0
  12. package/dist/client/transport.mjs.map +1 -0
  13. package/dist/index.d.mts +1 -0
  14. package/dist/index.mjs +1 -0
  15. package/dist/loop/accumulator.d.mts +11 -0
  16. package/dist/loop/accumulator.d.mts.map +1 -0
  17. package/dist/loop/accumulator.mjs +40 -0
  18. package/dist/loop/accumulator.mjs.map +1 -0
  19. package/dist/loop/error.d.mts +36 -0
  20. package/dist/loop/error.d.mts.map +1 -0
  21. package/dist/loop/error.mjs +84 -0
  22. package/dist/loop/error.mjs.map +1 -0
  23. package/dist/loop/index.d.mts +9 -0
  24. package/dist/loop/index.mjs +9 -0
  25. package/dist/loop/llm-event.d.mts +44 -0
  26. package/dist/loop/llm-event.d.mts.map +1 -0
  27. package/dist/loop/llm-event.mjs +34 -0
  28. package/dist/loop/llm-event.mjs.map +1 -0
  29. package/dist/loop/run.d.mts +37 -0
  30. package/dist/loop/run.d.mts.map +1 -0
  31. package/dist/loop/run.mjs +624 -0
  32. package/dist/loop/run.mjs.map +1 -0
  33. package/dist/loop/services/context-transformer.d.mts +18 -0
  34. package/dist/loop/services/context-transformer.d.mts.map +1 -0
  35. package/dist/loop/services/context-transformer.mjs +12 -0
  36. package/dist/loop/services/context-transformer.mjs.map +1 -0
  37. package/dist/loop/services/llm-provider.d.mts +20 -0
  38. package/dist/loop/services/llm-provider.d.mts.map +1 -0
  39. package/dist/loop/services/llm-provider.mjs +7 -0
  40. package/dist/loop/services/llm-provider.mjs.map +1 -0
  41. package/dist/loop/services/loop-config.d.mts +17 -0
  42. package/dist/loop/services/loop-config.d.mts.map +1 -0
  43. package/dist/loop/services/loop-config.mjs +15 -0
  44. package/dist/loop/services/loop-config.mjs.map +1 -0
  45. package/dist/loop/services/tool-executor.d.mts +12 -0
  46. package/dist/loop/services/tool-executor.d.mts.map +1 -0
  47. package/dist/loop/services/tool-executor.mjs +7 -0
  48. package/dist/loop/services/tool-executor.mjs.map +1 -0
  49. package/dist/loop/testing/faux-provider.d.mts +31 -0
  50. package/dist/loop/testing/faux-provider.d.mts.map +1 -0
  51. package/dist/loop/testing/faux-provider.mjs +47 -0
  52. package/dist/loop/testing/faux-provider.mjs.map +1 -0
  53. package/dist/loop/testing/index.d.mts +3 -0
  54. package/dist/loop/testing/index.mjs +3 -0
  55. package/dist/loop/testing/test-tool-executor.d.mts +10 -0
  56. package/dist/loop/testing/test-tool-executor.d.mts.map +1 -0
  57. package/dist/loop/testing/test-tool-executor.mjs +21 -0
  58. package/dist/loop/testing/test-tool-executor.mjs.map +1 -0
  59. package/dist/protocol/capability.d.mts +20 -0
  60. package/dist/protocol/capability.d.mts.map +1 -0
  61. package/dist/protocol/capability.mjs +34 -0
  62. package/dist/protocol/capability.mjs.map +1 -0
  63. package/dist/protocol/content.d.mts +31 -0
  64. package/dist/protocol/content.d.mts.map +1 -0
  65. package/dist/protocol/content.mjs +52 -0
  66. package/dist/protocol/content.mjs.map +1 -0
  67. package/dist/protocol/event.d.mts +228 -0
  68. package/dist/protocol/event.d.mts.map +1 -0
  69. package/dist/protocol/event.mjs +217 -0
  70. package/dist/protocol/event.mjs.map +1 -0
  71. package/dist/protocol/index.d.mts +14 -0
  72. package/dist/protocol/index.d.mts.map +1 -0
  73. package/dist/protocol/index.mjs +9 -0
  74. package/dist/protocol/message.d.mts +53 -0
  75. package/dist/protocol/message.d.mts.map +1 -0
  76. package/dist/protocol/message.mjs +49 -0
  77. package/dist/protocol/message.mjs.map +1 -0
  78. package/dist/protocol/reasoning.d.mts +8 -0
  79. package/dist/protocol/reasoning.d.mts.map +1 -0
  80. package/dist/protocol/reasoning.mjs +13 -0
  81. package/dist/protocol/reasoning.mjs.map +1 -0
  82. package/dist/protocol/session.d.mts +39 -0
  83. package/dist/protocol/session.d.mts.map +1 -0
  84. package/dist/protocol/session.mjs +38 -0
  85. package/dist/protocol/session.mjs.map +1 -0
  86. package/dist/protocol/tool.d.mts +101 -0
  87. package/dist/protocol/tool.d.mts.map +1 -0
  88. package/dist/protocol/tool.mjs +102 -0
  89. package/dist/protocol/tool.mjs.map +1 -0
  90. package/dist/protocol/usage.d.mts +26 -0
  91. package/dist/protocol/usage.d.mts.map +1 -0
  92. package/dist/protocol/usage.mjs +40 -0
  93. package/dist/protocol/usage.mjs.map +1 -0
  94. package/dist/runtime/error.d.mts +29 -0
  95. package/dist/runtime/error.d.mts.map +1 -0
  96. package/dist/runtime/error.mjs +46 -0
  97. package/dist/runtime/error.mjs.map +1 -0
  98. package/dist/runtime/index.d.mts +9 -0
  99. package/dist/runtime/index.d.mts.map +1 -0
  100. package/dist/runtime/index.mjs +4 -0
  101. package/dist/runtime/run-runtime.d.mts +47 -0
  102. package/dist/runtime/run-runtime.d.mts.map +1 -0
  103. package/dist/runtime/run-runtime.mjs +112 -0
  104. package/dist/runtime/run-runtime.mjs.map +1 -0
  105. package/dist/runtime/session-event-store.d.mts +75 -0
  106. package/dist/runtime/session-event-store.d.mts.map +1 -0
  107. package/dist/runtime/session-event-store.mjs +124 -0
  108. package/dist/runtime/session-event-store.mjs.map +1 -0
  109. package/dist/tools/index.d.mts +4 -0
  110. package/dist/tools/index.mjs +4 -0
  111. package/dist/tools/question.d.mts +21 -0
  112. package/dist/tools/question.d.mts.map +1 -0
  113. package/dist/tools/question.mjs +41 -0
  114. package/dist/tools/question.mjs.map +1 -0
  115. package/dist/tools/registry.d.mts +61 -0
  116. package/dist/tools/registry.d.mts.map +1 -0
  117. package/dist/tools/registry.mjs +113 -0
  118. package/dist/tools/registry.mjs.map +1 -0
  119. package/dist/tools/task.d.mts +34 -0
  120. package/dist/tools/task.d.mts.map +1 -0
  121. package/dist/tools/task.mjs +81 -0
  122. package/dist/tools/task.mjs.map +1 -0
  123. package/package.json +86 -0
  124. package/src/client/README.md +23 -0
  125. package/src/client/index.ts +43 -0
  126. package/src/client/state.ts +380 -0
  127. package/src/client/transport.ts +517 -0
  128. package/src/index.ts +2 -0
  129. package/src/loop/README.md +23 -0
  130. package/src/loop/accumulator.ts +71 -0
  131. package/src/loop/error.ts +105 -0
  132. package/src/loop/index.ts +35 -0
  133. package/src/loop/llm-event.ts +52 -0
  134. package/src/loop/run.ts +1237 -0
  135. package/src/loop/services/context-transformer.ts +24 -0
  136. package/src/loop/services/llm-provider.ts +20 -0
  137. package/src/loop/services/loop-config.ts +20 -0
  138. package/src/loop/services/tool-executor.ts +11 -0
  139. package/src/loop/testing/faux-provider.ts +94 -0
  140. package/src/loop/testing/index.ts +3 -0
  141. package/src/loop/testing/test-tool-executor.ts +28 -0
  142. package/src/protocol/README.md +24 -0
  143. package/src/protocol/capability.ts +29 -0
  144. package/src/protocol/content.ts +76 -0
  145. package/src/protocol/event.ts +286 -0
  146. package/src/protocol/index.ts +109 -0
  147. package/src/protocol/message.ts +86 -0
  148. package/src/protocol/reasoning.ts +4 -0
  149. package/src/protocol/session.ts +47 -0
  150. package/src/protocol/tool.ts +154 -0
  151. package/src/protocol/usage.ts +48 -0
  152. package/src/runtime/README.md +44 -0
  153. package/src/runtime/error.ts +70 -0
  154. package/src/runtime/index.ts +43 -0
  155. package/src/runtime/run-runtime.ts +307 -0
  156. package/src/runtime/session-event-store.ts +254 -0
  157. package/src/tools/README.md +22 -0
  158. package/src/tools/index.ts +29 -0
  159. package/src/tools/question.ts +58 -0
  160. package/src/tools/registry.ts +228 -0
  161. package/src/tools/task.ts +132 -0
@@ -0,0 +1,109 @@
1
+ export {
2
+ AgentContentCapabilities,
3
+ AgentModelCapabilities,
4
+ textImageModelCapabilities,
5
+ textOnlyModelCapabilities
6
+ } from './capability.ts'
7
+ export {
8
+ appendTextToContent,
9
+ AudioPart,
10
+ Content,
11
+ ContentPart,
12
+ contentParts,
13
+ contentPartPreview,
14
+ contentPartText,
15
+ contentPreview,
16
+ contentText,
17
+ ImagePart,
18
+ isContentEmpty,
19
+ TextPart
20
+ } from './content.ts'
21
+ export {
22
+ AgentAwaitingInput,
23
+ AgentEnd,
24
+ AgentError,
25
+ AgentErrorCode,
26
+ AgentEvent,
27
+ AgentRetry,
28
+ AgentStart,
29
+ AssistantMessageEvent,
30
+ CompactionEnd,
31
+ CompactionStart,
32
+ LLMReasoningDelta,
33
+ LLMStreamEnd,
34
+ LLMStreamStart,
35
+ LLMTextDelta,
36
+ ProviderToolResult,
37
+ QuestionAnswered,
38
+ QuestionCancelled,
39
+ QuestionRequested,
40
+ SubagentCompleted,
41
+ SubagentStarted,
42
+ SubagentStatus,
43
+ ToolApprovalDenied,
44
+ ToolApprovalGranted,
45
+ ToolApprovalRequested,
46
+ ToolExecutionCompleted,
47
+ ToolExecutionError,
48
+ ToolExecutionStarted,
49
+ ToolInputDelta,
50
+ ToolInputEnd,
51
+ ToolInputStart,
52
+ TurnEnd,
53
+ TurnStart,
54
+ UsageUpdate
55
+ } from './event.ts'
56
+ export {
57
+ AgentMessage,
58
+ AssistantAgentMessage,
59
+ AssistantPart,
60
+ AssistantReasoningPart,
61
+ AssistantTextPart,
62
+ HostToolCallPart,
63
+ ProviderToolCallPart,
64
+ ProviderToolResultPart,
65
+ ToolResultMessage,
66
+ UserMessage,
67
+ assistantContent,
68
+ assistantHostToolCalls,
69
+ assistantReasoningText
70
+ } from './message.ts'
71
+ export { AgentReasoningEffort } from './reasoning.ts'
72
+ export {
73
+ AgentWebSocketClientMessage,
74
+ AgentWebSocketServerMessage,
75
+ SessionSnapshot,
76
+ QuestionResponseInput,
77
+ ToolApprovalResponseInput,
78
+ UserInput
79
+ } from './session.ts'
80
+ export {
81
+ HitlRequest,
82
+ HitlResponse,
83
+ HitlResponseSource,
84
+ QuestionAnswer,
85
+ QuestionOption,
86
+ QuestionPrompt,
87
+ QuestionRequest,
88
+ QuestionResponse,
89
+ QuestionResponseOutcome,
90
+ QuestionToolParams,
91
+ formatQuestionResponseContent,
92
+ ToolApprovalDecision,
93
+ ToolApprovalMode,
94
+ ToolApprovalPolicy,
95
+ ToolApprovalRequest,
96
+ ToolApprovalResponse,
97
+ ToolCall,
98
+ ToolDef,
99
+ ToolResult
100
+ } from './tool.ts'
101
+ export {
102
+ addAgentUsage,
103
+ AgentInputUsage,
104
+ AgentOutputUsage,
105
+ AgentUsage,
106
+ zeroAgentUsage
107
+ } from './usage.ts'
108
+
109
+ export type MessageId = string
@@ -0,0 +1,86 @@
1
+ import * as Schema from 'effect/Schema'
2
+ import { Content, contentParts } from './content.ts'
3
+ import { ToolCall, ToolResult } from './tool.ts'
4
+
5
+ export class UserMessage extends Schema.TaggedClass<UserMessage>()('User', {
6
+ content: Content
7
+ }) {}
8
+
9
+ export class AssistantTextPart extends Schema.TaggedClass<AssistantTextPart>()('Text', {
10
+ content: Content
11
+ }) {}
12
+
13
+ export class AssistantReasoningPart extends Schema.TaggedClass<AssistantReasoningPart>()(
14
+ 'Reasoning',
15
+ {
16
+ text: Schema.String
17
+ }
18
+ ) {}
19
+
20
+ export class HostToolCallPart extends Schema.TaggedClass<HostToolCallPart>()('HostToolCall', {
21
+ call: ToolCall
22
+ }) {}
23
+
24
+ export class ProviderToolCallPart extends Schema.TaggedClass<ProviderToolCallPart>()(
25
+ 'ProviderToolCall',
26
+ {
27
+ call: ToolCall,
28
+ providerMetadata: Schema.optional(Schema.Unknown)
29
+ }
30
+ ) {}
31
+
32
+ export class ProviderToolResultPart extends Schema.TaggedClass<ProviderToolResultPart>()(
33
+ 'ProviderToolResult',
34
+ {
35
+ toolCallId: Schema.String,
36
+ result: ToolResult,
37
+ providerMetadata: Schema.optional(Schema.Unknown)
38
+ }
39
+ ) {}
40
+
41
+ export const AssistantPart = Schema.Union([
42
+ AssistantTextPart,
43
+ AssistantReasoningPart,
44
+ HostToolCallPart,
45
+ ProviderToolCallPart,
46
+ ProviderToolResultPart
47
+ ])
48
+ export type AssistantPart = typeof AssistantPart.Type
49
+
50
+ export class AssistantAgentMessage extends Schema.TaggedClass<AssistantAgentMessage>()(
51
+ 'Assistant',
52
+ {
53
+ parts: Schema.Array(AssistantPart)
54
+ }
55
+ ) {}
56
+
57
+ export class ToolResultMessage extends Schema.TaggedClass<ToolResultMessage>()('ToolResult', {
58
+ toolCallId: Schema.String,
59
+ content: Content,
60
+ isError: Schema.optional(Schema.Boolean),
61
+ structuredContent: Schema.optional(Schema.Unknown)
62
+ }) {}
63
+
64
+ export const AgentMessage = Schema.Union([UserMessage, AssistantAgentMessage, ToolResultMessage])
65
+ export type AgentMessage = typeof AgentMessage.Type
66
+
67
+ export const assistantContent = (message: AssistantAgentMessage): Content => {
68
+ const parts = message.parts.flatMap(part => (part._tag === 'Text' ? [part.content] : []))
69
+ const first = parts[0]
70
+
71
+ if (parts.length === 0) {
72
+ return ''
73
+ }
74
+
75
+ if (parts.length === 1 && first !== undefined) {
76
+ return first
77
+ }
78
+
79
+ return parts.flatMap(contentParts)
80
+ }
81
+
82
+ export const assistantReasoningText = (message: AssistantAgentMessage) =>
83
+ message.parts.flatMap(part => (part._tag === 'Reasoning' ? [part.text] : [])).join('')
84
+
85
+ export const assistantHostToolCalls = (message: AssistantAgentMessage) =>
86
+ message.parts.flatMap(part => (part._tag === 'HostToolCall' ? [part.call] : []))
@@ -0,0 +1,4 @@
1
+ import * as Schema from 'effect/Schema'
2
+
3
+ export const AgentReasoningEffort = Schema.Literals(['minimal', 'low', 'medium', 'high', 'xhigh'])
4
+ export type AgentReasoningEffort = typeof AgentReasoningEffort.Type
@@ -0,0 +1,47 @@
1
+ import * as Schema from 'effect/Schema'
2
+ import { AgentEvent } from './event.ts'
3
+ import { AgentMessage, UserMessage } from './message.ts'
4
+ import { AgentReasoningEffort } from './reasoning.ts'
5
+ import { QuestionResponse, ToolApprovalResponse } from './tool.ts'
6
+
7
+ export class SessionSnapshot extends Schema.TaggedClass<SessionSnapshot>()('SessionSnapshot', {
8
+ revision: Schema.Number,
9
+ messages: Schema.Array(AgentMessage)
10
+ }) {}
11
+
12
+ export class UserInput extends Schema.TaggedClass<UserInput>()('UserInput', {
13
+ message: UserMessage,
14
+ expectedRevision: Schema.optional(Schema.Number),
15
+ model: Schema.optional(Schema.String),
16
+ reasoningEffort: Schema.optional(AgentReasoningEffort)
17
+ }) {}
18
+
19
+ export class ToolApprovalResponseInput extends Schema.TaggedClass<ToolApprovalResponseInput>()(
20
+ 'ToolApprovalResponseInput',
21
+ {
22
+ response: ToolApprovalResponse,
23
+ expectedRevision: Schema.optional(Schema.Number),
24
+ model: Schema.optional(Schema.String),
25
+ reasoningEffort: Schema.optional(AgentReasoningEffort)
26
+ }
27
+ ) {}
28
+
29
+ export class QuestionResponseInput extends Schema.TaggedClass<QuestionResponseInput>()(
30
+ 'QuestionResponseInput',
31
+ {
32
+ response: QuestionResponse,
33
+ expectedRevision: Schema.optional(Schema.Number),
34
+ model: Schema.optional(Schema.String),
35
+ reasoningEffort: Schema.optional(AgentReasoningEffort)
36
+ }
37
+ ) {}
38
+
39
+ export const AgentWebSocketClientMessage = Schema.Union([
40
+ UserInput,
41
+ ToolApprovalResponseInput,
42
+ QuestionResponseInput
43
+ ])
44
+ export type AgentWebSocketClientMessage = typeof AgentWebSocketClientMessage.Type
45
+
46
+ export const AgentWebSocketServerMessage = Schema.Union([SessionSnapshot, AgentEvent])
47
+ export type AgentWebSocketServerMessage = typeof AgentWebSocketServerMessage.Type
@@ -0,0 +1,154 @@
1
+ import * as Schema from 'effect/Schema'
2
+ import { Content } from './content.ts'
3
+
4
+ const NonEmptyTrimmedString = Schema.Trimmed.pipe(Schema.check(Schema.isNonEmpty()))
5
+
6
+ export const HitlResponseSource = Schema.Literals(['user', 'policy', 'replay'])
7
+ export type HitlResponseSource = typeof HitlResponseSource.Type
8
+
9
+ export const ToolApprovalDecision = Schema.Literals(['approved', 'denied'])
10
+ export type ToolApprovalDecision = typeof ToolApprovalDecision.Type
11
+
12
+ export const ToolApprovalMode = Schema.Literals(['manual'])
13
+ export type ToolApprovalMode = typeof ToolApprovalMode.Type
14
+
15
+ export class ToolApprovalPolicy extends Schema.Class<ToolApprovalPolicy>('ToolApprovalPolicy')({
16
+ mode: ToolApprovalMode,
17
+ reason: Schema.optional(Schema.String)
18
+ }) {}
19
+
20
+ export class ToolCall extends Schema.Class<ToolCall>('ToolCall')({
21
+ id: NonEmptyTrimmedString,
22
+ name: NonEmptyTrimmedString,
23
+ params: Schema.Unknown
24
+ }) {}
25
+
26
+ export class ToolDef extends Schema.Class<ToolDef>('ToolDef')({
27
+ name: NonEmptyTrimmedString,
28
+ description: Schema.String,
29
+ parameters: Schema.Unknown,
30
+ approval: Schema.optional(ToolApprovalPolicy)
31
+ }) {}
32
+
33
+ export class ToolResult extends Schema.Class<ToolResult>('ToolResult')({
34
+ toolCallId: NonEmptyTrimmedString,
35
+ content: Content,
36
+ isError: Schema.optional(Schema.Boolean),
37
+ structuredContent: Schema.optional(Schema.Unknown)
38
+ }) {}
39
+
40
+ export class ToolApprovalRequest extends Schema.TaggedClass<ToolApprovalRequest>()(
41
+ 'ToolApprovalRequest',
42
+ {
43
+ requestId: NonEmptyTrimmedString,
44
+ toolCallId: NonEmptyTrimmedString,
45
+ call: ToolCall,
46
+ policy: Schema.optional(ToolApprovalPolicy)
47
+ }
48
+ ) {}
49
+
50
+ export class ToolApprovalResponse extends Schema.TaggedClass<ToolApprovalResponse>()(
51
+ 'ToolApprovalResponse',
52
+ {
53
+ requestId: NonEmptyTrimmedString,
54
+ toolCallId: NonEmptyTrimmedString,
55
+ decision: ToolApprovalDecision,
56
+ source: HitlResponseSource,
57
+ reason: Schema.optional(Schema.String)
58
+ }
59
+ ) {}
60
+
61
+ export class QuestionOption extends Schema.Class<QuestionOption>('QuestionOption')({
62
+ id: NonEmptyTrimmedString,
63
+ label: NonEmptyTrimmedString,
64
+ description: Schema.optional(Schema.String)
65
+ }) {}
66
+
67
+ export class QuestionPrompt extends Schema.Class<QuestionPrompt>('QuestionPrompt')({
68
+ id: NonEmptyTrimmedString,
69
+ prompt: NonEmptyTrimmedString,
70
+ options: Schema.optional(Schema.Array(QuestionOption)),
71
+ multiple: Schema.optional(Schema.Boolean),
72
+ allowCustom: Schema.optional(Schema.Boolean),
73
+ required: Schema.optional(Schema.Boolean)
74
+ }) {}
75
+
76
+ export class QuestionToolParams extends Schema.Class<QuestionToolParams>('QuestionToolParams')({
77
+ questions: Schema.NonEmptyArray(QuestionPrompt)
78
+ }) {}
79
+
80
+ export class QuestionRequest extends Schema.TaggedClass<QuestionRequest>()('QuestionRequest', {
81
+ requestId: NonEmptyTrimmedString,
82
+ toolCallId: NonEmptyTrimmedString,
83
+ call: ToolCall,
84
+ questions: Schema.NonEmptyArray(QuestionPrompt)
85
+ }) {}
86
+
87
+ export class QuestionAnswer extends Schema.Class<QuestionAnswer>('QuestionAnswer')({
88
+ questionId: NonEmptyTrimmedString,
89
+ optionIds: Schema.optional(Schema.Array(NonEmptyTrimmedString)),
90
+ customAnswer: Schema.optional(Schema.String)
91
+ }) {}
92
+
93
+ export const QuestionResponseOutcome = Schema.Literals(['answered', 'cancelled'])
94
+ export type QuestionResponseOutcome = typeof QuestionResponseOutcome.Type
95
+
96
+ export class QuestionResponse extends Schema.TaggedClass<QuestionResponse>()('QuestionResponse', {
97
+ requestId: NonEmptyTrimmedString,
98
+ toolCallId: NonEmptyTrimmedString,
99
+ outcome: QuestionResponseOutcome,
100
+ source: HitlResponseSource,
101
+ answers: Schema.optional(Schema.Array(QuestionAnswer)),
102
+ reason: Schema.optional(Schema.String)
103
+ }) {}
104
+
105
+ const optionLabel = (question: QuestionPrompt, optionId: string) =>
106
+ question.options?.find(option => option.id === optionId)?.label ?? optionId
107
+
108
+ const questionForAnswer = (
109
+ questions: ReadonlyArray<QuestionPrompt>,
110
+ answer: QuestionAnswer
111
+ ) => questions.find(question => question.id === answer.questionId)
112
+
113
+ const formatQuestionAnswer = (
114
+ answer: QuestionAnswer,
115
+ questions: ReadonlyArray<QuestionPrompt>
116
+ ) => {
117
+ const question = questionForAnswer(questions, answer)
118
+ const prompt = question?.prompt ?? answer.questionId
119
+ const selected = answer.optionIds?.map(optionId =>
120
+ question === undefined ? optionId : optionLabel(question, optionId)
121
+ ) ?? []
122
+ const custom = answer.customAnswer?.trim()
123
+ const values = custom === undefined || custom.length === 0 ? selected : [...selected, custom]
124
+
125
+ return values.length === 0 ? `- ${prompt}: answered` : `- ${prompt}: ${values.join(', ')}`
126
+ }
127
+
128
+ export const formatQuestionResponseContent = (
129
+ response: QuestionResponse,
130
+ questions: ReadonlyArray<QuestionPrompt> = []
131
+ ) => {
132
+ if (response.outcome === 'cancelled') {
133
+ return `Question cancelled: ${response.reason ?? 'Question cancelled'}`
134
+ }
135
+
136
+ const answers = response.answers ?? []
137
+
138
+ if (answers.length === 0) {
139
+ return 'User answered the question, but no answer values were provided. Continue with this in mind.'
140
+ }
141
+
142
+ const formatted = answers
143
+ .map(answer => formatQuestionAnswer(answer, questions).slice('- '.length))
144
+ .join('; ')
145
+ const label = answers.length === 1 ? 'question' : 'questions'
146
+
147
+ return `User has answered your ${label}: ${formatted}. Continue with the user's answers in mind.`
148
+ }
149
+
150
+ export const HitlRequest = Schema.Union([ToolApprovalRequest, QuestionRequest])
151
+ export type HitlRequest = typeof HitlRequest.Type
152
+
153
+ export const HitlResponse = Schema.Union([ToolApprovalResponse, QuestionResponse])
154
+ export type HitlResponse = typeof HitlResponse.Type
@@ -0,0 +1,48 @@
1
+ import { Array as Arr, Option } from 'effect'
2
+ import * as Schema from 'effect/Schema'
3
+
4
+ export class AgentInputUsage extends Schema.Class<AgentInputUsage>('AgentInputUsage')({
5
+ total: Schema.Number,
6
+ uncached: Schema.optional(Schema.Number),
7
+ cacheRead: Schema.optional(Schema.Number),
8
+ cacheWrite: Schema.optional(Schema.Number)
9
+ }) {}
10
+
11
+ export class AgentOutputUsage extends Schema.Class<AgentOutputUsage>('AgentOutputUsage')({
12
+ total: Schema.Number,
13
+ text: Schema.optional(Schema.Number),
14
+ reasoning: Schema.optional(Schema.Number)
15
+ }) {}
16
+
17
+ export class AgentUsage extends Schema.Class<AgentUsage>('AgentUsage')({
18
+ input: AgentInputUsage,
19
+ output: AgentOutputUsage
20
+ }) {}
21
+
22
+ export const zeroAgentUsage = AgentUsage.make({
23
+ input: AgentInputUsage.make({ total: 0 }),
24
+ output: AgentOutputUsage.make({ total: 0 })
25
+ })
26
+
27
+ const sumOptional = (left: number | undefined, right: number | undefined) =>
28
+ Option.getOrUndefined(
29
+ Option.liftPredicate(
30
+ Arr.getSomes([Option.fromNullishOr(left), Option.fromNullishOr(right)]),
31
+ values => values.length > 0
32
+ ).pipe(Option.map(values => Arr.reduce(values, 0, (sum, value) => sum + value)))
33
+ )
34
+
35
+ export const addAgentUsage = (left: AgentUsage, right: AgentUsage) =>
36
+ AgentUsage.make({
37
+ input: AgentInputUsage.make({
38
+ total: left.input.total + right.input.total,
39
+ uncached: sumOptional(left.input.uncached, right.input.uncached),
40
+ cacheRead: sumOptional(left.input.cacheRead, right.input.cacheRead),
41
+ cacheWrite: sumOptional(left.input.cacheWrite, right.input.cacheWrite)
42
+ }),
43
+ output: AgentOutputUsage.make({
44
+ total: left.output.total + right.output.total,
45
+ text: sumOptional(left.output.text, right.output.text),
46
+ reasoning: sumOptional(left.output.reasoning, right.output.reasoning)
47
+ })
48
+ })
@@ -0,0 +1,44 @@
1
+ # @yolk-sdk/agent/runtime
2
+
3
+ Generic session orchestration for `@yolk-sdk/agent/loop`.
4
+
5
+ ## What it provides
6
+
7
+ - `runRuntime` for stateless transcript runs or append-backed durable runs.
8
+ - `SessionEventStore` service contract for append-only runtime session events.
9
+ - In-memory session event store layer for tests/simple hosts.
10
+ - Runtime-specific errors.
11
+ - Pending HITL state and response replay for durable sessions.
12
+
13
+ ## Request modes
14
+
15
+ ### `Transcript`
16
+
17
+ Use `Transcript` when the caller owns replay state. The caller passes a complete protocol transcript and runtime does not load or persist session state.
18
+
19
+ ### `AppendInput`
20
+
21
+ Use `AppendInput` when the host wants durable runtime persistence. Runtime:
22
+
23
+ 1. loads the prior `SessionEventStore` log,
24
+ 2. replays protocol `AgentMessage` values from `InputAppended` and `RunCompleted`,
25
+ 3. appends `InputAppended` and `RunStarted`,
26
+ 4. runs the loop,
27
+ 5. appends `RunCompleted`, `RunAwaitingInput`, or `RunFailed`.
28
+
29
+ ### `AppendHitlResponse`
30
+
31
+ Use `AppendHitlResponse` to persist one approval/question response and resume a paused append-backed run.
32
+
33
+ Hosts own physical storage, auth/tenancy, reconnect/fanout, and cleanup policy. Use numeric `expectedRevision` to reject stale writes. Use `latestIncompleteRuntimeRun` to decide when a host should append `RunInterrupted`.
34
+
35
+ ## Use it when
36
+
37
+ - You need reusable lifecycle around the stateless loop.
38
+ - Your app owns storage and wants to inject it through an Effect service.
39
+
40
+ ## Boundaries
41
+
42
+ - No database implementation.
43
+ - No HTTP/WebSocket routes.
44
+ - No app auth or tenancy logic.
@@ -0,0 +1,70 @@
1
+ import * as Schema from 'effect/Schema'
2
+ import { agentLoopErrorToAgentError, type AgentLoopError } from '@yolk-sdk/agent/loop'
3
+ import { AgentError } from '@yolk-sdk/agent/protocol'
4
+
5
+ export class SessionNotFoundError extends Schema.TaggedErrorClass<SessionNotFoundError>()(
6
+ 'SessionNotFoundError',
7
+ {
8
+ sessionId: Schema.String
9
+ }
10
+ ) {}
11
+
12
+ export class SessionLoadError extends Schema.TaggedErrorClass<SessionLoadError>()(
13
+ 'SessionLoadError',
14
+ {
15
+ sessionId: Schema.String,
16
+ message: Schema.String
17
+ }
18
+ ) {}
19
+
20
+ export class SessionSaveError extends Schema.TaggedErrorClass<SessionSaveError>()(
21
+ 'SessionSaveError',
22
+ {
23
+ sessionId: Schema.String,
24
+ message: Schema.String
25
+ }
26
+ ) {}
27
+
28
+ export class SessionConflictError extends Schema.TaggedErrorClass<SessionConflictError>()(
29
+ 'SessionConflictError',
30
+ {
31
+ sessionId: Schema.String,
32
+ message: Schema.String
33
+ }
34
+ ) {}
35
+
36
+ export type RuntimeError =
37
+ | SessionNotFoundError
38
+ | SessionLoadError
39
+ | SessionSaveError
40
+ | SessionConflictError
41
+
42
+ export const runtimeErrorToAgentError = (error: RuntimeError | AgentLoopError): AgentError => {
43
+ switch (error._tag) {
44
+ case 'SessionNotFoundError':
45
+ return AgentError.make({
46
+ code: 'session_not_found',
47
+ message: `Session not found: ${error.sessionId}`,
48
+ retryable: false
49
+ })
50
+ case 'SessionLoadError':
51
+ case 'SessionSaveError':
52
+ return AgentError.make({
53
+ code: 'store_error',
54
+ message: error.message,
55
+ retryable: true
56
+ })
57
+ case 'SessionConflictError':
58
+ return AgentError.make({
59
+ code: 'conflict',
60
+ message: error.message,
61
+ retryable: false
62
+ })
63
+ case 'LLMError':
64
+ case 'ToolError':
65
+ case 'ContextTransformError':
66
+ case 'AbortError':
67
+ case 'FauxExhaustedError':
68
+ return agentLoopErrorToAgentError(error)
69
+ }
70
+ }
@@ -0,0 +1,43 @@
1
+ export {
2
+ runtimeErrorToAgentError,
3
+ SessionConflictError,
4
+ SessionLoadError,
5
+ SessionNotFoundError,
6
+ SessionSaveError
7
+ } from './error.ts'
8
+ export type { RuntimeError } from './error.ts'
9
+ export { runRuntime } from './run-runtime.ts'
10
+ export type {
11
+ AppendInputRuntimeRequest,
12
+ AppendHitlResponseRuntimeRequest,
13
+ RuntimeConfig,
14
+ RuntimeRequest,
15
+ RuntimeTranscript,
16
+ TranscriptRuntimeRequest
17
+ } from './run-runtime.ts'
18
+ export {
19
+ appendRuntimeSessionEventsToLog,
20
+ HitlResponseAppended,
21
+ InputAppended,
22
+ makeInMemorySessionEventStoreLayer,
23
+ latestIncompleteRuntimeRun,
24
+ replayRuntimeHitlResponses,
25
+ replayRuntimeSessionEvents,
26
+ RunAwaitingInput,
27
+ RunCompleted,
28
+ RunFailed,
29
+ RunInterrupted,
30
+ RunStarted,
31
+ RuntimeSessionEvent,
32
+ SessionEventStore
33
+ } from './session-event-store.ts'
34
+ export type {
35
+ AppendRuntimeSessionEventsInput,
36
+ IncompleteRuntimeRun,
37
+ RuntimeSessionEventLog,
38
+ SessionEventStoreApi,
39
+ SessionRevision,
40
+ StoredRuntimeSessionEvent
41
+ } from './session-event-store.ts'
42
+
43
+ export type RuntimeSessionId = string