@llm4ts/core 0.1.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 (284) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/AgentSession.d.ts +66 -0
  4. package/dist/AgentSession.d.ts.map +1 -0
  5. package/dist/AgentSession.js +53 -0
  6. package/dist/AgentSession.js.map +1 -0
  7. package/dist/Capability.d.ts +101 -0
  8. package/dist/Capability.d.ts.map +1 -0
  9. package/dist/Capability.js +210 -0
  10. package/dist/Capability.js.map +1 -0
  11. package/dist/Connector.d.ts +69 -0
  12. package/dist/Connector.d.ts.map +1 -0
  13. package/dist/Connector.js +86 -0
  14. package/dist/Connector.js.map +1 -0
  15. package/dist/ConnectorConfig.d.ts +70 -0
  16. package/dist/ConnectorConfig.d.ts.map +1 -0
  17. package/dist/ConnectorConfig.js +110 -0
  18. package/dist/ConnectorConfig.js.map +1 -0
  19. package/dist/ConnectorRegistry.d.ts +28 -0
  20. package/dist/ConnectorRegistry.d.ts.map +1 -0
  21. package/dist/ConnectorRegistry.js +87 -0
  22. package/dist/ConnectorRegistry.js.map +1 -0
  23. package/dist/ContextManagement.d.ts +78 -0
  24. package/dist/ContextManagement.d.ts.map +1 -0
  25. package/dist/ContextManagement.js +221 -0
  26. package/dist/ContextManagement.js.map +1 -0
  27. package/dist/Conversation.d.ts +18 -0
  28. package/dist/Conversation.d.ts.map +1 -0
  29. package/dist/Conversation.js +17 -0
  30. package/dist/Conversation.js.map +1 -0
  31. package/dist/Errors.d.ts +64 -0
  32. package/dist/Errors.d.ts.map +1 -0
  33. package/dist/Errors.js +76 -0
  34. package/dist/Errors.js.map +1 -0
  35. package/dist/HttpClient.d.ts +43 -0
  36. package/dist/HttpClient.d.ts.map +1 -0
  37. package/dist/HttpClient.js +99 -0
  38. package/dist/HttpClient.js.map +1 -0
  39. package/dist/LlmService.d.ts +24 -0
  40. package/dist/LlmService.d.ts.map +1 -0
  41. package/dist/LlmService.js +4 -0
  42. package/dist/LlmService.js.map +1 -0
  43. package/dist/Models.d.ts +138 -0
  44. package/dist/Models.d.ts.map +1 -0
  45. package/dist/Models.js +209 -0
  46. package/dist/Models.js.map +1 -0
  47. package/dist/ProcessExecutor.d.ts +57 -0
  48. package/dist/ProcessExecutor.d.ts.map +1 -0
  49. package/dist/ProcessExecutor.js +71 -0
  50. package/dist/ProcessExecutor.js.map +1 -0
  51. package/dist/RateLimiter.d.ts +44 -0
  52. package/dist/RateLimiter.d.ts.map +1 -0
  53. package/dist/RateLimiter.js +155 -0
  54. package/dist/RateLimiter.js.map +1 -0
  55. package/dist/Streaming.d.ts +17 -0
  56. package/dist/Streaming.d.ts.map +1 -0
  57. package/dist/Streaming.js +65 -0
  58. package/dist/Streaming.js.map +1 -0
  59. package/dist/StructuredOutput.d.ts +10 -0
  60. package/dist/StructuredOutput.d.ts.map +1 -0
  61. package/dist/StructuredOutput.js +97 -0
  62. package/dist/StructuredOutput.js.map +1 -0
  63. package/dist/TemporaryFiles.d.ts +20 -0
  64. package/dist/TemporaryFiles.d.ts.map +1 -0
  65. package/dist/TemporaryFiles.js +18 -0
  66. package/dist/TemporaryFiles.js.map +1 -0
  67. package/dist/UsageLimits.d.ts +5 -0
  68. package/dist/UsageLimits.d.ts.map +1 -0
  69. package/dist/UsageLimits.js +187 -0
  70. package/dist/UsageLimits.js.map +1 -0
  71. package/dist/eval/Checks.d.ts +6 -0
  72. package/dist/eval/Checks.d.ts.map +1 -0
  73. package/dist/eval/Checks.js +39 -0
  74. package/dist/eval/Checks.js.map +1 -0
  75. package/dist/eval/Eval.d.ts +57 -0
  76. package/dist/eval/Eval.d.ts.map +1 -0
  77. package/dist/eval/Eval.js +91 -0
  78. package/dist/eval/Eval.js.map +1 -0
  79. package/dist/eval/EvalSuite.d.ts +21 -0
  80. package/dist/eval/EvalSuite.d.ts.map +1 -0
  81. package/dist/eval/EvalSuite.js +30 -0
  82. package/dist/eval/EvalSuite.js.map +1 -0
  83. package/dist/eval/Evaluator.d.ts +10 -0
  84. package/dist/eval/Evaluator.d.ts.map +1 -0
  85. package/dist/eval/Evaluator.js +14 -0
  86. package/dist/eval/Evaluator.js.map +1 -0
  87. package/dist/eval/Judge.d.ts +15 -0
  88. package/dist/eval/Judge.d.ts.map +1 -0
  89. package/dist/eval/Judge.js +73 -0
  90. package/dist/eval/Judge.js.map +1 -0
  91. package/dist/observability/MeteredLlmService.d.ts +16 -0
  92. package/dist/observability/MeteredLlmService.d.ts.map +1 -0
  93. package/dist/observability/MeteredLlmService.js +66 -0
  94. package/dist/observability/MeteredLlmService.js.map +1 -0
  95. package/dist/observability/Metrics.d.ts +71 -0
  96. package/dist/observability/Metrics.d.ts.map +1 -0
  97. package/dist/observability/Metrics.js +147 -0
  98. package/dist/observability/Metrics.js.map +1 -0
  99. package/dist/observability/Redaction.d.ts +8 -0
  100. package/dist/observability/Redaction.d.ts.map +1 -0
  101. package/dist/observability/Redaction.js +38 -0
  102. package/dist/observability/Redaction.js.map +1 -0
  103. package/dist/observability/StreamRecorder.d.ts +9 -0
  104. package/dist/observability/StreamRecorder.d.ts.map +1 -0
  105. package/dist/observability/StreamRecorder.js +10 -0
  106. package/dist/observability/StreamRecorder.js.map +1 -0
  107. package/dist/observability/StructuredLogger.d.ts +31 -0
  108. package/dist/observability/StructuredLogger.d.ts.map +1 -0
  109. package/dist/observability/StructuredLogger.js +34 -0
  110. package/dist/observability/StructuredLogger.js.map +1 -0
  111. package/dist/observability/Tracing.d.ts +38 -0
  112. package/dist/observability/Tracing.d.ts.map +1 -0
  113. package/dist/observability/Tracing.js +75 -0
  114. package/dist/observability/Tracing.js.map +1 -0
  115. package/dist/providers/AnthropicModels.d.ts +95 -0
  116. package/dist/providers/AnthropicModels.d.ts.map +1 -0
  117. package/dist/providers/AnthropicModels.js +83 -0
  118. package/dist/providers/AnthropicModels.js.map +1 -0
  119. package/dist/providers/AnthropicProvider.d.ts +13 -0
  120. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  121. package/dist/providers/AnthropicProvider.js +177 -0
  122. package/dist/providers/AnthropicProvider.js.map +1 -0
  123. package/dist/providers/AntigravityConnector.d.ts +7 -0
  124. package/dist/providers/AntigravityConnector.d.ts.map +1 -0
  125. package/dist/providers/AntigravityConnector.js +52 -0
  126. package/dist/providers/AntigravityConnector.js.map +1 -0
  127. package/dist/providers/ClaudeAgentSession.d.ts +11 -0
  128. package/dist/providers/ClaudeAgentSession.d.ts.map +1 -0
  129. package/dist/providers/ClaudeAgentSession.js +158 -0
  130. package/dist/providers/ClaudeAgentSession.js.map +1 -0
  131. package/dist/providers/ClaudeCliConnector.d.ts +9 -0
  132. package/dist/providers/ClaudeCliConnector.d.ts.map +1 -0
  133. package/dist/providers/ClaudeCliConnector.js +123 -0
  134. package/dist/providers/ClaudeCliConnector.js.map +1 -0
  135. package/dist/providers/CliSupport.d.ts +21 -0
  136. package/dist/providers/CliSupport.d.ts.map +1 -0
  137. package/dist/providers/CliSupport.js +62 -0
  138. package/dist/providers/CliSupport.js.map +1 -0
  139. package/dist/providers/CodexConnector.d.ts +12 -0
  140. package/dist/providers/CodexConnector.d.ts.map +1 -0
  141. package/dist/providers/CodexConnector.js +175 -0
  142. package/dist/providers/CodexConnector.js.map +1 -0
  143. package/dist/providers/ConnectorFactories.d.ts +15 -0
  144. package/dist/providers/ConnectorFactories.d.ts.map +1 -0
  145. package/dist/providers/ConnectorFactories.js +74 -0
  146. package/dist/providers/ConnectorFactories.js.map +1 -0
  147. package/dist/providers/CopilotConnector.d.ts +6 -0
  148. package/dist/providers/CopilotConnector.d.ts.map +1 -0
  149. package/dist/providers/CopilotConnector.js +35 -0
  150. package/dist/providers/CopilotConnector.js.map +1 -0
  151. package/dist/providers/CursorConnector.d.ts +8 -0
  152. package/dist/providers/CursorConnector.d.ts.map +1 -0
  153. package/dist/providers/CursorConnector.js +82 -0
  154. package/dist/providers/CursorConnector.js.map +1 -0
  155. package/dist/providers/GeminiApiProvider.d.ts +9 -0
  156. package/dist/providers/GeminiApiProvider.d.ts.map +1 -0
  157. package/dist/providers/GeminiApiProvider.js +181 -0
  158. package/dist/providers/GeminiApiProvider.js.map +1 -0
  159. package/dist/providers/GeminiCliProvider.d.ts +106 -0
  160. package/dist/providers/GeminiCliProvider.d.ts.map +1 -0
  161. package/dist/providers/GeminiCliProvider.js +596 -0
  162. package/dist/providers/GeminiCliProvider.js.map +1 -0
  163. package/dist/providers/GeminiModels.d.ts +92 -0
  164. package/dist/providers/GeminiModels.d.ts.map +1 -0
  165. package/dist/providers/GeminiModels.js +80 -0
  166. package/dist/providers/GeminiModels.js.map +1 -0
  167. package/dist/providers/GrokCliConnector.d.ts +8 -0
  168. package/dist/providers/GrokCliConnector.d.ts.map +1 -0
  169. package/dist/providers/GrokCliConnector.js +82 -0
  170. package/dist/providers/GrokCliConnector.js.map +1 -0
  171. package/dist/providers/LmStudioModels.d.ts +114 -0
  172. package/dist/providers/LmStudioModels.d.ts.map +1 -0
  173. package/dist/providers/LmStudioModels.js +102 -0
  174. package/dist/providers/LmStudioModels.js.map +1 -0
  175. package/dist/providers/LmStudioProvider.d.ts +13 -0
  176. package/dist/providers/LmStudioProvider.d.ts.map +1 -0
  177. package/dist/providers/LmStudioProvider.js +158 -0
  178. package/dist/providers/LmStudioProvider.js.map +1 -0
  179. package/dist/providers/MockProvider.d.ts +6 -0
  180. package/dist/providers/MockProvider.d.ts.map +1 -0
  181. package/dist/providers/MockProvider.js +271 -0
  182. package/dist/providers/MockProvider.js.map +1 -0
  183. package/dist/providers/OllamaModels.d.ts +68 -0
  184. package/dist/providers/OllamaModels.d.ts.map +1 -0
  185. package/dist/providers/OllamaModels.js +59 -0
  186. package/dist/providers/OllamaModels.js.map +1 -0
  187. package/dist/providers/OllamaProvider.d.ts +7 -0
  188. package/dist/providers/OllamaProvider.d.ts.map +1 -0
  189. package/dist/providers/OllamaProvider.js +134 -0
  190. package/dist/providers/OllamaProvider.js.map +1 -0
  191. package/dist/providers/OpenAIModels.d.ts +139 -0
  192. package/dist/providers/OpenAIModels.d.ts.map +1 -0
  193. package/dist/providers/OpenAIModels.js +123 -0
  194. package/dist/providers/OpenAIModels.js.map +1 -0
  195. package/dist/providers/OpenAIProvider.d.ts +9 -0
  196. package/dist/providers/OpenAIProvider.d.ts.map +1 -0
  197. package/dist/providers/OpenAIProvider.js +185 -0
  198. package/dist/providers/OpenAIProvider.js.map +1 -0
  199. package/dist/providers/OpenCodeCliConnector.d.ts +8 -0
  200. package/dist/providers/OpenCodeCliConnector.d.ts.map +1 -0
  201. package/dist/providers/OpenCodeCliConnector.js +93 -0
  202. package/dist/providers/OpenCodeCliConnector.js.map +1 -0
  203. package/dist/providers/OpenCodeModels.d.ts +61 -0
  204. package/dist/providers/OpenCodeModels.d.ts.map +1 -0
  205. package/dist/providers/OpenCodeModels.js +53 -0
  206. package/dist/providers/OpenCodeModels.js.map +1 -0
  207. package/dist/providers/OpenCodeProvider.d.ts +10 -0
  208. package/dist/providers/OpenCodeProvider.d.ts.map +1 -0
  209. package/dist/providers/OpenCodeProvider.js +154 -0
  210. package/dist/providers/OpenCodeProvider.js.map +1 -0
  211. package/dist/providers/PiConnector.d.ts +8 -0
  212. package/dist/providers/PiConnector.d.ts.map +1 -0
  213. package/dist/providers/PiConnector.js +99 -0
  214. package/dist/providers/PiConnector.js.map +1 -0
  215. package/dist/tools/Tool.d.ts +83 -0
  216. package/dist/tools/Tool.d.ts.map +1 -0
  217. package/dist/tools/Tool.js +278 -0
  218. package/dist/tools/Tool.js.map +1 -0
  219. package/dist/tools/ToolCallingExecutor.d.ts +18 -0
  220. package/dist/tools/ToolCallingExecutor.d.ts.map +1 -0
  221. package/dist/tools/ToolCallingExecutor.js +64 -0
  222. package/dist/tools/ToolCallingExecutor.js.map +1 -0
  223. package/dist/tools/ToolRegistry.d.ts +45 -0
  224. package/dist/tools/ToolRegistry.d.ts.map +1 -0
  225. package/dist/tools/ToolRegistry.js +133 -0
  226. package/dist/tools/ToolRegistry.js.map +1 -0
  227. package/package.json +105 -0
  228. package/src/.gitkeep +1 -0
  229. package/src/AgentSession.ts +69 -0
  230. package/src/Capability.ts +240 -0
  231. package/src/Connector.ts +220 -0
  232. package/src/ConnectorConfig.ts +146 -0
  233. package/src/ConnectorRegistry.ts +184 -0
  234. package/src/ContextManagement.ts +372 -0
  235. package/src/Conversation.ts +21 -0
  236. package/src/Errors.ts +87 -0
  237. package/src/HttpClient.ts +202 -0
  238. package/src/LlmService.ts +45 -0
  239. package/src/Models.ts +250 -0
  240. package/src/ProcessExecutor.ts +157 -0
  241. package/src/RateLimiter.ts +238 -0
  242. package/src/Streaming.ts +164 -0
  243. package/src/StructuredOutput.ts +138 -0
  244. package/src/TemporaryFiles.ts +51 -0
  245. package/src/UsageLimits.ts +242 -0
  246. package/src/eval/Checks.ts +68 -0
  247. package/src/eval/Eval.ts +112 -0
  248. package/src/eval/EvalSuite.ts +63 -0
  249. package/src/eval/Evaluator.ts +31 -0
  250. package/src/eval/Judge.ts +92 -0
  251. package/src/observability/MeteredLlmService.ts +156 -0
  252. package/src/observability/Metrics.ts +195 -0
  253. package/src/observability/Redaction.ts +55 -0
  254. package/src/observability/StreamRecorder.ts +32 -0
  255. package/src/observability/StructuredLogger.ts +62 -0
  256. package/src/observability/Tracing.ts +141 -0
  257. package/src/providers/AnthropicModels.ts +96 -0
  258. package/src/providers/AnthropicProvider.ts +320 -0
  259. package/src/providers/AntigravityConnector.ts +77 -0
  260. package/src/providers/ClaudeAgentSession.ts +226 -0
  261. package/src/providers/ClaudeCliConnector.ts +201 -0
  262. package/src/providers/CliSupport.ts +100 -0
  263. package/src/providers/CodexConnector.ts +251 -0
  264. package/src/providers/ConnectorFactories.ts +142 -0
  265. package/src/providers/CopilotConnector.ts +47 -0
  266. package/src/providers/CursorConnector.ts +120 -0
  267. package/src/providers/GeminiApiProvider.ts +337 -0
  268. package/src/providers/GeminiCliProvider.ts +793 -0
  269. package/src/providers/GeminiModels.ts +97 -0
  270. package/src/providers/GrokCliConnector.ts +117 -0
  271. package/src/providers/LmStudioModels.ts +117 -0
  272. package/src/providers/LmStudioProvider.ts +260 -0
  273. package/src/providers/MockProvider.ts +322 -0
  274. package/src/providers/OllamaModels.ts +64 -0
  275. package/src/providers/OllamaProvider.ts +236 -0
  276. package/src/providers/OpenAIModels.ts +152 -0
  277. package/src/providers/OpenAIProvider.ts +331 -0
  278. package/src/providers/OpenCodeCliConnector.ts +135 -0
  279. package/src/providers/OpenCodeModels.ts +60 -0
  280. package/src/providers/OpenCodeProvider.ts +278 -0
  281. package/src/providers/PiConnector.ts +142 -0
  282. package/src/tools/Tool.ts +379 -0
  283. package/src/tools/ToolCallingExecutor.ts +106 -0
  284. package/src/tools/ToolRegistry.ts +224 -0
@@ -0,0 +1,152 @@
1
+ import * as Effect from "effect/Effect"
2
+ import * as Schema from "effect/Schema"
3
+ import { JsonSchema } from "../Models.ts"
4
+
5
+ export class OpenAIJsonSchemaSpec extends Schema.Class<OpenAIJsonSchemaSpec>(
6
+ "OpenAIJsonSchemaSpec"
7
+ )({
8
+ name: Schema.String,
9
+ schema: JsonSchema
10
+ }) {}
11
+
12
+ export class OpenAIResponseFormat extends Schema.Class<OpenAIResponseFormat>(
13
+ "OpenAIResponseFormat"
14
+ )({
15
+ type: Schema.String,
16
+ json_schema: Schema.optionalKey(OpenAIJsonSchemaSpec)
17
+ }) {}
18
+
19
+ export class OpenAIChatMessage extends Schema.Class<OpenAIChatMessage>("OpenAIChatMessage")({
20
+ role: Schema.String,
21
+ content: Schema.String
22
+ }) {}
23
+
24
+ export class OpenAIChatCompletionRequest extends Schema.Class<OpenAIChatCompletionRequest>(
25
+ "OpenAIChatCompletionRequest"
26
+ )({
27
+ model: Schema.String,
28
+ messages: Schema.Array(OpenAIChatMessage),
29
+ temperature: Schema.optionalKey(Schema.Number),
30
+ max_tokens: Schema.optionalKey(Schema.Int),
31
+ max_completion_tokens: Schema.optionalKey(Schema.Int),
32
+ stream: Schema.optionalKey(Schema.Boolean),
33
+ response_format: Schema.optionalKey(OpenAIResponseFormat)
34
+ }) {}
35
+
36
+ export class OpenAITokenUsage extends Schema.Class<OpenAITokenUsage>("OpenAITokenUsage")({
37
+ prompt_tokens: Schema.optionalKey(Schema.Int),
38
+ completion_tokens: Schema.optionalKey(Schema.Int),
39
+ total_tokens: Schema.optionalKey(Schema.Int)
40
+ }) {}
41
+
42
+ export class OpenAIChatResponseMessage extends Schema.Class<OpenAIChatResponseMessage>(
43
+ "OpenAIChatResponseMessage"
44
+ )({
45
+ role: Schema.String,
46
+ content: Schema.NullOr(Schema.String)
47
+ }) {}
48
+
49
+ export class OpenAIChatChoice extends Schema.Class<OpenAIChatChoice>("OpenAIChatChoice")({
50
+ index: Schema.Int.pipe(Schema.withConstructorDefault(Effect.succeed(0))),
51
+ message: Schema.optionalKey(OpenAIChatResponseMessage),
52
+ text: Schema.optionalKey(Schema.NullOr(Schema.String)),
53
+ finish_reason: Schema.optionalKey(Schema.NullOr(Schema.String))
54
+ }) {}
55
+
56
+ export class OpenAIChatCompletionResponse extends Schema.Class<OpenAIChatCompletionResponse>(
57
+ "OpenAIChatCompletionResponse"
58
+ )({
59
+ id: Schema.optionalKey(Schema.String),
60
+ choices: Schema.Array(OpenAIChatChoice),
61
+ usage: Schema.optionalKey(OpenAITokenUsage),
62
+ model: Schema.optionalKey(Schema.String)
63
+ }) {}
64
+
65
+ export class OpenAIFunction extends Schema.Class<OpenAIFunction>("OpenAIFunction")({
66
+ name: Schema.String,
67
+ description: Schema.String,
68
+ parameters: JsonSchema
69
+ }) {}
70
+
71
+ export class OpenAITool extends Schema.Class<OpenAITool>("OpenAITool")({
72
+ type: Schema.String.pipe(Schema.withConstructorDefault(Effect.succeed("function"))),
73
+ function: OpenAIFunction
74
+ }) {}
75
+
76
+ export class OpenAIToolCallFunction extends Schema.Class<OpenAIToolCallFunction>(
77
+ "OpenAIToolCallFunction"
78
+ )({
79
+ name: Schema.String,
80
+ arguments: Schema.String
81
+ }) {}
82
+
83
+ export class OpenAIToolCall extends Schema.Class<OpenAIToolCall>("OpenAIToolCall")({
84
+ id: Schema.String,
85
+ type: Schema.String,
86
+ function: OpenAIToolCallFunction
87
+ }) {}
88
+
89
+ const noToolCalls: ReadonlyArray<OpenAIToolCall> = Object.freeze([])
90
+
91
+ export class OpenAIChatMessageWithTools extends Schema.Class<OpenAIChatMessageWithTools>(
92
+ "OpenAIChatMessageWithTools"
93
+ )({
94
+ role: Schema.String,
95
+ content: Schema.optionalKey(Schema.NullOr(Schema.String)),
96
+ tool_calls: Schema.Array(OpenAIToolCall).pipe(
97
+ Schema.withConstructorDefault(Effect.succeed(noToolCalls))
98
+ )
99
+ }) {}
100
+
101
+ export class OpenAIChatChoiceWithTools extends Schema.Class<OpenAIChatChoiceWithTools>(
102
+ "OpenAIChatChoiceWithTools"
103
+ )({
104
+ index: Schema.Int.pipe(Schema.withConstructorDefault(Effect.succeed(0))),
105
+ message: Schema.optionalKey(OpenAIChatMessageWithTools),
106
+ finish_reason: Schema.optionalKey(Schema.NullOr(Schema.String))
107
+ }) {}
108
+
109
+ export class OpenAIChatCompletionResponseWithTools extends Schema.Class<OpenAIChatCompletionResponseWithTools>(
110
+ "OpenAIChatCompletionResponseWithTools"
111
+ )({
112
+ id: Schema.optionalKey(Schema.String),
113
+ choices: Schema.Array(OpenAIChatChoiceWithTools),
114
+ usage: Schema.optionalKey(OpenAITokenUsage),
115
+ model: Schema.optionalKey(Schema.String)
116
+ }) {}
117
+
118
+ export class OpenAIChatCompletionRequestWithTools extends Schema.Class<OpenAIChatCompletionRequestWithTools>(
119
+ "OpenAIChatCompletionRequestWithTools"
120
+ )({
121
+ model: Schema.String,
122
+ messages: Schema.Array(OpenAIChatMessage),
123
+ tools: Schema.Array(OpenAITool),
124
+ temperature: Schema.optionalKey(Schema.Number),
125
+ max_tokens: Schema.optionalKey(Schema.Int),
126
+ stream: Schema.optionalKey(Schema.Boolean)
127
+ }) {}
128
+
129
+ export class OpenAIChatChunkDelta extends Schema.Class<OpenAIChatChunkDelta>(
130
+ "OpenAIChatChunkDelta"
131
+ )({
132
+ role: Schema.optionalKey(Schema.String),
133
+ content: Schema.optionalKey(Schema.NullOr(Schema.String))
134
+ }) {}
135
+
136
+ export class OpenAIChatChunkChoice extends Schema.Class<OpenAIChatChunkChoice>(
137
+ "OpenAIChatChunkChoice"
138
+ )({
139
+ index: Schema.Int.pipe(Schema.withConstructorDefault(Effect.succeed(0))),
140
+ delta: Schema.optionalKey(OpenAIChatChunkDelta),
141
+ finish_reason: Schema.optionalKey(Schema.NullOr(Schema.String))
142
+ }) {}
143
+
144
+ const noChunkChoices: ReadonlyArray<OpenAIChatChunkChoice> = Object.freeze([])
145
+
146
+ export class OpenAIChatChunk extends Schema.Class<OpenAIChatChunk>("OpenAIChatChunk")({
147
+ id: Schema.optionalKey(Schema.String),
148
+ model: Schema.optionalKey(Schema.String),
149
+ choices: Schema.Array(OpenAIChatChunkChoice).pipe(
150
+ Schema.withConstructorDefault(Effect.succeed(noChunkChoices))
151
+ )
152
+ }) {}
@@ -0,0 +1,331 @@
1
+ import * as Effect from "effect/Effect"
2
+ import * as Redacted from "effect/Redacted"
3
+ import * as Schema from "effect/Schema"
4
+ import * as Stream from "effect/Stream"
5
+ import { makeApiConnector, type ApiConnectorShape } from "../Connector.ts"
6
+ import { AuthenticationError, ConfigError, ParseError, type LlmError } from "../Errors.ts"
7
+ import type { HttpClientShape } from "../HttpClient.ts"
8
+ import type { StructuredResult } from "../LlmService.ts"
9
+ import {
10
+ ConnectorIds,
11
+ LlmChunk,
12
+ ToolCall,
13
+ ToolCallResponse,
14
+ type JsonSchema,
15
+ type LlmConfig,
16
+ type Message,
17
+ type MessageRole,
18
+ type ToolDefinition
19
+ } from "../Models.ts"
20
+ import { parseFromText } from "../StructuredOutput.ts"
21
+ import {
22
+ OpenAIChatChunk,
23
+ OpenAIChatCompletionRequest,
24
+ OpenAIChatCompletionRequestWithTools,
25
+ OpenAIChatCompletionResponse,
26
+ OpenAIChatCompletionResponseWithTools,
27
+ OpenAIChatMessage,
28
+ OpenAIFunction,
29
+ OpenAIJsonSchemaSpec,
30
+ OpenAIResponseFormat,
31
+ OpenAITool
32
+ } from "./OpenAIModels.ts"
33
+
34
+ const emptyHeaders: Readonly<Record<string, string>> = Object.freeze({})
35
+
36
+ interface RequiredConfig {
37
+ readonly baseUrl: string
38
+ }
39
+
40
+ const normalizedBaseUrl = (baseUrl: string): string => baseUrl.replace(/\/+$/, "")
41
+
42
+ const roleName = (role: MessageRole): string => {
43
+ switch (role) {
44
+ case "System":
45
+ return "system"
46
+ case "User":
47
+ return "user"
48
+ case "Assistant":
49
+ return "assistant"
50
+ case "Tool":
51
+ return "tool"
52
+ }
53
+ }
54
+
55
+ export const openAIHistoryMessages = (
56
+ messages: ReadonlyArray<Message>
57
+ ): ReadonlyArray<OpenAIChatMessage> =>
58
+ messages.map((message) =>
59
+ OpenAIChatMessage.make({
60
+ role: roleName(message.role),
61
+ content: message.content
62
+ })
63
+ )
64
+
65
+ export const buildOpenAIChatRequest = (
66
+ config: LlmConfig,
67
+ messages: ReadonlyArray<OpenAIChatMessage>,
68
+ stream: boolean,
69
+ responseFormat?: OpenAIResponseFormat
70
+ ): OpenAIChatCompletionRequest =>
71
+ OpenAIChatCompletionRequest.make({
72
+ model: config.model,
73
+ messages,
74
+ temperature: config.temperature ?? 0.7,
75
+ stream,
76
+ ...(config.maxTokens === undefined ? {} : { max_tokens: config.maxTokens }),
77
+ ...(responseFormat === undefined ? {} : { response_format: responseFormat })
78
+ })
79
+
80
+ export const buildOpenAIToolRequest = (
81
+ config: LlmConfig,
82
+ prompt: string,
83
+ tools: ReadonlyArray<ToolDefinition>
84
+ ): OpenAIChatCompletionRequestWithTools =>
85
+ OpenAIChatCompletionRequestWithTools.make({
86
+ model: config.model,
87
+ messages: [
88
+ OpenAIChatMessage.make({
89
+ role: "user",
90
+ content: prompt
91
+ })
92
+ ],
93
+ tools: tools.map((tool) =>
94
+ OpenAITool.make({
95
+ function: OpenAIFunction.make({
96
+ name: tool.name,
97
+ description: tool.description,
98
+ parameters: tool.parameters
99
+ })
100
+ })
101
+ ),
102
+ temperature: config.temperature ?? 0.7,
103
+ stream: false,
104
+ ...(config.maxTokens === undefined ? {} : { max_tokens: config.maxTokens })
105
+ })
106
+
107
+ const decodeCompletionResponse = (
108
+ raw: string
109
+ ): Effect.Effect<OpenAIChatCompletionResponse, ParseError> =>
110
+ schemaDecode.completion(raw).pipe(
111
+ Effect.mapError((error) =>
112
+ ParseError.make({
113
+ message: `Failed to decode OpenAI response: ${String(error)}`,
114
+ raw
115
+ })
116
+ )
117
+ )
118
+
119
+ const decodeToolResponse = (
120
+ raw: string
121
+ ): Effect.Effect<OpenAIChatCompletionResponseWithTools, ParseError> =>
122
+ schemaDecode.tools(raw).pipe(
123
+ Effect.mapError((error) =>
124
+ ParseError.make({
125
+ message: `Failed to decode OpenAI tool response: ${String(error)}`,
126
+ raw
127
+ })
128
+ )
129
+ )
130
+
131
+ const decodeStreamChunk = (raw: string): Effect.Effect<OpenAIChatChunk, ParseError> =>
132
+ schemaDecode.chunk(raw).pipe(
133
+ Effect.mapError((error) =>
134
+ ParseError.make({
135
+ message: `Failed to parse OpenAI stream chunk: ${String(error)}`,
136
+ raw
137
+ })
138
+ )
139
+ )
140
+
141
+ const schemaDecode = {
142
+ completion: Schema.decodeUnknownEffect(Schema.fromJsonString(OpenAIChatCompletionResponse)),
143
+ tools: Schema.decodeUnknownEffect(Schema.fromJsonString(OpenAIChatCompletionResponseWithTools)),
144
+ chunk: Schema.decodeUnknownEffect(Schema.fromJsonString(OpenAIChatChunk))
145
+ }
146
+
147
+ const extractContent = (
148
+ response: OpenAIChatCompletionResponse,
149
+ raw: string
150
+ ): Effect.Effect<string, ParseError> => {
151
+ const content = response.choices[0]?.message?.content?.trim()
152
+ return content === undefined || content === null || content.length === 0
153
+ ? Effect.fail(
154
+ ParseError.make({
155
+ message: "OpenAI response missing choices[0].message.content",
156
+ raw
157
+ })
158
+ )
159
+ : Effect.succeed(content)
160
+ }
161
+
162
+ export const makeOpenAIProvider = (
163
+ config: LlmConfig,
164
+ httpClient: HttpClientShape
165
+ ): ApiConnectorShape => {
166
+ const authHeaders = (): Readonly<Record<string, string>> =>
167
+ config.apiKey === undefined
168
+ ? emptyHeaders
169
+ : { Authorization: `Bearer ${Redacted.value(config.apiKey)}` }
170
+
171
+ const requiredConfig: Effect.Effect<RequiredConfig, LlmError> =
172
+ config.baseUrl === undefined
173
+ ? Effect.fail(
174
+ ConfigError.make({
175
+ message: "Missing baseUrl for OpenAI provider"
176
+ })
177
+ )
178
+ : config.apiKey === undefined
179
+ ? Effect.fail(
180
+ AuthenticationError.make({
181
+ message:
182
+ "Missing API key for OpenAI provider (set OPENAI_API_KEY or pass apiKey in the connector config)"
183
+ })
184
+ )
185
+ : Effect.succeed({
186
+ baseUrl: normalizedBaseUrl(config.baseUrl)
187
+ })
188
+
189
+ const executeRequest = (
190
+ messages: ReadonlyArray<OpenAIChatMessage>,
191
+ responseFormat?: OpenAIResponseFormat
192
+ ): Effect.Effect<readonly [response: OpenAIChatCompletionResponse, raw: string], LlmError> =>
193
+ Effect.gen(function* () {
194
+ const { baseUrl } = yield* requiredConfig
195
+ const request = buildOpenAIChatRequest(config, messages, false, responseFormat)
196
+ const raw = yield* httpClient.postJson(
197
+ `${baseUrl}/chat/completions`,
198
+ JSON.stringify(request),
199
+ authHeaders(),
200
+ config.timeout
201
+ )
202
+ const response = yield* decodeCompletionResponse(raw)
203
+ return [response, raw]
204
+ })
205
+
206
+ const executeStreamRequest = (
207
+ messages: ReadonlyArray<OpenAIChatMessage>
208
+ ): Stream.Stream<LlmChunk, LlmError> =>
209
+ Stream.unwrap(
210
+ Effect.map(requiredConfig, ({ baseUrl }) => {
211
+ const request = buildOpenAIChatRequest(config, messages, true)
212
+ return httpClient
213
+ .postJsonStreamSSE(
214
+ `${baseUrl}/chat/completions`,
215
+ JSON.stringify(request),
216
+ authHeaders(),
217
+ config.timeout
218
+ )
219
+ .pipe(
220
+ Stream.mapEffect(decodeStreamChunk),
221
+ Stream.flatMap((chunk) => {
222
+ const choice = chunk.choices[0]
223
+ const delta = choice?.delta?.content ?? ""
224
+ const finishReason = choice?.finish_reason ?? undefined
225
+ return delta.length > 0 || finishReason !== undefined
226
+ ? Stream.succeed(
227
+ LlmChunk.make({
228
+ delta,
229
+ metadata: {
230
+ provider: "openai",
231
+ model: config.model
232
+ },
233
+ ...(finishReason === undefined ? {} : { finishReason })
234
+ })
235
+ )
236
+ : Stream.empty
237
+ })
238
+ )
239
+ })
240
+ )
241
+
242
+ const executeStructuredWithUsage = <A, E, RD, RE>(
243
+ prompt: string,
244
+ schema: Schema.ConstraintCodec<A, E, RD, RE>,
245
+ jsonSchema: JsonSchema
246
+ ): Effect.Effect<StructuredResult<A>, LlmError, RD> =>
247
+ Effect.gen(function* () {
248
+ const responseFormat = OpenAIResponseFormat.make({
249
+ type: "json_schema",
250
+ json_schema: OpenAIJsonSchemaSpec.make({
251
+ name: "response",
252
+ schema: jsonSchema
253
+ })
254
+ })
255
+ const [response, raw] = yield* executeRequest(
256
+ [
257
+ OpenAIChatMessage.make({
258
+ role: "user",
259
+ content: prompt
260
+ })
261
+ ],
262
+ responseFormat
263
+ )
264
+ const content = yield* extractContent(response, raw)
265
+ const value = yield* parseFromText(content, schema, jsonSchema)
266
+ const result: StructuredResult<A> = [value, undefined, undefined]
267
+ return result
268
+ })
269
+
270
+ const executeWithTools = (
271
+ prompt: string,
272
+ tools: ReadonlyArray<ToolDefinition>
273
+ ): Effect.Effect<ToolCallResponse, LlmError> =>
274
+ Effect.gen(function* () {
275
+ const { baseUrl } = yield* requiredConfig
276
+ const request = buildOpenAIToolRequest(config, prompt, tools)
277
+ const raw = yield* httpClient.postJson(
278
+ `${baseUrl}/chat/completions`,
279
+ JSON.stringify(request),
280
+ authHeaders(),
281
+ config.timeout
282
+ )
283
+ const response = yield* decodeToolResponse(raw)
284
+ const choice = response.choices[0]
285
+ const toolCalls =
286
+ choice?.message?.tool_calls.map((toolCall) =>
287
+ ToolCall.make({
288
+ id: toolCall.id,
289
+ name: toolCall.function.name,
290
+ arguments: toolCall.function.arguments
291
+ })
292
+ ) ?? []
293
+ const content = choice?.message?.content ?? undefined
294
+ const finishReason = choice?.finish_reason ?? "stop"
295
+
296
+ return ToolCallResponse.make({
297
+ toolCalls,
298
+ finishReason,
299
+ ...(content === undefined || content === null ? {} : { content })
300
+ })
301
+ })
302
+
303
+ // Parity with llm4zio v4.2.0 OpenAIProvider.isAvailable (`catchAll(_ => ZIO.succeed(true))`):
304
+ // a configured baseUrl counts as available even when the /models probe fails.
305
+ const isAvailable: Effect.Effect<boolean> =
306
+ config.baseUrl === undefined
307
+ ? Effect.succeed(false)
308
+ : httpClient
309
+ .get(`${normalizedBaseUrl(config.baseUrl)}/models`, authHeaders(), config.timeout)
310
+ .pipe(
311
+ Effect.match({
312
+ onFailure: () => true,
313
+ onSuccess: () => true
314
+ })
315
+ )
316
+
317
+ return makeApiConnector({
318
+ id: ConnectorIds.OpenAI,
319
+ executeStream: (prompt) =>
320
+ executeStreamRequest([
321
+ OpenAIChatMessage.make({
322
+ role: "user",
323
+ content: prompt
324
+ })
325
+ ]),
326
+ executeStreamWithHistory: (messages) => executeStreamRequest(openAIHistoryMessages(messages)),
327
+ executeWithTools,
328
+ executeStructuredWithUsage,
329
+ isAvailable
330
+ })
331
+ }
@@ -0,0 +1,135 @@
1
+ import * as Effect from "effect/Effect"
2
+ import * as Stream from "effect/Stream"
3
+ import { makeCliConnector, type CliConnectorShape } from "../Connector.ts"
4
+ import type { CliConnectorConfig } from "../ConnectorConfig.ts"
5
+ import { ConnectorIds, LlmChunk, TokenUsage } from "../Models.ts"
6
+ import type { ProcessExecutorShape } from "../ProcessExecutor.ts"
7
+ import {
8
+ failClassifiedCliError,
9
+ jsonField,
10
+ jsonIntField,
11
+ jsonStringField,
12
+ optionalModelArgs,
13
+ parseJsonLine,
14
+ sortedFlagArgs,
15
+ toolEventChunk,
16
+ usageEventChunk
17
+ } from "./CliSupport.ts"
18
+
19
+ export const openCodeCliExtraArgs = (config: CliConnectorConfig): ReadonlyArray<string> => [
20
+ ...optionalModelArgs(config.model),
21
+ ...(config.readOnly ? ["--agent", "plan"] : ["--auto"]),
22
+ ...sortedFlagArgs(config.flags)
23
+ ]
24
+
25
+ export const parseOpenCodeCliStreamLine = (line: string): ReadonlyArray<LlmChunk> => {
26
+ const json = parseJsonLine(line)
27
+ if (json === undefined) {
28
+ return []
29
+ }
30
+
31
+ const part = jsonField(json, "part")
32
+ switch (jsonStringField(json, "type")) {
33
+ case "text": {
34
+ const text = jsonStringField(part, "text")
35
+ return text === undefined || text.length === 0 ? [] : [LlmChunk.make({ delta: text })]
36
+ }
37
+ case "tool_use":
38
+ return part === undefined
39
+ ? []
40
+ : [
41
+ toolEventChunk(
42
+ jsonStringField(part, "tool") ?? "",
43
+ jsonField(jsonField(part, "state"), "input")
44
+ )
45
+ ]
46
+ case "step_finish": {
47
+ const tokens = jsonField(part, "tokens")
48
+ if (tokens === undefined) {
49
+ return []
50
+ }
51
+ const prompt = jsonIntField(tokens, "input") ?? 0
52
+ const completion = jsonIntField(tokens, "output") ?? 0
53
+ const cached = jsonIntField(jsonField(tokens, "cache"), "read")
54
+ return [
55
+ usageEventChunk(
56
+ undefined,
57
+ TokenUsage.make({
58
+ prompt,
59
+ completion,
60
+ total: jsonIntField(tokens, "total") ?? prompt + completion,
61
+ ...(cached === undefined ? {} : { cached })
62
+ })
63
+ )
64
+ ]
65
+ }
66
+ case "error":
67
+ return [
68
+ LlmChunk.make({
69
+ delta: "",
70
+ metadata: {
71
+ opencodeError:
72
+ jsonStringField(json, "error") ?? jsonStringField(json, "message") ?? "opencode error"
73
+ }
74
+ })
75
+ ]
76
+ default:
77
+ return []
78
+ }
79
+ }
80
+
81
+ export const makeOpenCodeCliConnector = (
82
+ config: CliConnectorConfig,
83
+ executor: ProcessExecutorShape
84
+ ): CliConnectorShape => {
85
+ const cwd = config.workingDir ?? "."
86
+ const extraArgs = openCodeCliExtraArgs(config)
87
+ const buildArgv = (prompt: string): ReadonlyArray<string> => [
88
+ "opencode",
89
+ "run",
90
+ ...extraArgs,
91
+ prompt
92
+ ]
93
+
94
+ const complete = Effect.fn("@llm4ts/core/providers/OpenCodeCliConnector.complete")(function* (
95
+ prompt: string
96
+ ) {
97
+ const result = yield* executor.run(buildArgv(prompt), cwd, config.envVars)
98
+ if (result.exitCode !== 0) {
99
+ const raw = result.stdout.join("\n")
100
+ return yield* failClassifiedCliError(
101
+ "opencode",
102
+ `opencode exited with code ${result.exitCode}`,
103
+ raw
104
+ )
105
+ }
106
+ return result.stdout.join("\n")
107
+ })
108
+
109
+ const completeStream = (prompt: string) =>
110
+ executor
111
+ .runStreaming(
112
+ ["opencode", "run", "--format", "json", ...extraArgs, prompt],
113
+ cwd,
114
+ config.envVars
115
+ )
116
+ .pipe(
117
+ Stream.flatMap((line) => Stream.fromIterable(parseOpenCodeCliStreamLine(line))),
118
+ Stream.mapEffect((chunk) => {
119
+ const message = chunk.metadata.opencodeError
120
+ return message === undefined
121
+ ? Effect.succeed(chunk)
122
+ : failClassifiedCliError("opencode", "opencode error", message)
123
+ })
124
+ )
125
+
126
+ return makeCliConnector({
127
+ id: ConnectorIds.OpenCode,
128
+ interactionSupport: "ContinuationOnly",
129
+ buildArgv: (prompt, _context) => buildArgv(prompt),
130
+ buildInteractiveArgv: (_context) => ["opencode"],
131
+ complete,
132
+ completeStream,
133
+ versionProbe: { executor, binary: "opencode", cwd }
134
+ })
135
+ }
@@ -0,0 +1,60 @@
1
+ import * as Schema from "effect/Schema"
2
+ import { JsonSchema } from "../Models.ts"
3
+
4
+ export class OpenCodeMessage extends Schema.Class<OpenCodeMessage>("OpenCodeMessage")({
5
+ role: Schema.String,
6
+ content: Schema.String
7
+ }) {}
8
+
9
+ export class OpenCodeJsonSchemaSpec extends Schema.Class<OpenCodeJsonSchemaSpec>(
10
+ "OpenCodeJsonSchemaSpec"
11
+ )({
12
+ name: Schema.String,
13
+ schema: JsonSchema
14
+ }) {}
15
+
16
+ export class OpenCodeResponseFormat extends Schema.Class<OpenCodeResponseFormat>(
17
+ "OpenCodeResponseFormat"
18
+ )({
19
+ type: Schema.String,
20
+ json_schema: Schema.optionalKey(OpenCodeJsonSchemaSpec)
21
+ }) {}
22
+
23
+ export class OpenCodeCompletionRequest extends Schema.Class<OpenCodeCompletionRequest>(
24
+ "OpenCodeCompletionRequest"
25
+ )({
26
+ model: Schema.String,
27
+ messages: Schema.Array(OpenCodeMessage),
28
+ temperature: Schema.optionalKey(Schema.Number),
29
+ max_tokens: Schema.optionalKey(Schema.Int),
30
+ max_completion_tokens: Schema.optionalKey(Schema.Int),
31
+ stream: Schema.optionalKey(Schema.Boolean),
32
+ response_format: Schema.optionalKey(OpenCodeResponseFormat)
33
+ }) {}
34
+
35
+ export class OpenCodeDelta extends Schema.Class<OpenCodeDelta>("OpenCodeDelta")({
36
+ content: Schema.optionalKey(Schema.NullOr(Schema.String))
37
+ }) {}
38
+
39
+ export class OpenCodeChoice extends Schema.Class<OpenCodeChoice>("OpenCodeChoice")({
40
+ index: Schema.optionalKey(Schema.Int),
41
+ message: Schema.optionalKey(OpenCodeMessage),
42
+ delta: Schema.optionalKey(OpenCodeDelta),
43
+ text: Schema.optionalKey(Schema.NullOr(Schema.String)),
44
+ finish_reason: Schema.optionalKey(Schema.NullOr(Schema.String))
45
+ }) {}
46
+
47
+ export class OpenCodeTokenUsage extends Schema.Class<OpenCodeTokenUsage>("OpenCodeTokenUsage")({
48
+ prompt_tokens: Schema.optionalKey(Schema.Int),
49
+ completion_tokens: Schema.optionalKey(Schema.Int),
50
+ total_tokens: Schema.optionalKey(Schema.Int)
51
+ }) {}
52
+
53
+ export class OpenCodeCompletionResponse extends Schema.Class<OpenCodeCompletionResponse>(
54
+ "OpenCodeCompletionResponse"
55
+ )({
56
+ id: Schema.optionalKey(Schema.String),
57
+ choices: Schema.Array(OpenCodeChoice),
58
+ usage: Schema.optionalKey(OpenCodeTokenUsage),
59
+ model: Schema.optionalKey(Schema.String)
60
+ }) {}