@llm4ts/core 2.54.0 → 3.0.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.
- package/README.md +1 -1
- package/dist/Capability.d.ts +0 -9
- package/dist/Capability.d.ts.map +1 -1
- package/dist/Capability.js +0 -38
- package/dist/Capability.js.map +1 -1
- package/dist/Connector.d.ts +2 -3
- package/dist/Connector.d.ts.map +1 -1
- package/dist/Connector.js +0 -5
- package/dist/Connector.js.map +1 -1
- package/dist/ConnectorRegistry.d.ts +0 -3
- package/dist/ConnectorRegistry.d.ts.map +1 -1
- package/dist/ConnectorRegistry.js +0 -3
- package/dist/ConnectorRegistry.js.map +1 -1
- package/dist/HttpClient.d.ts +0 -2
- package/dist/HttpClient.d.ts.map +1 -1
- package/dist/HttpClient.js +0 -2
- package/dist/HttpClient.js.map +1 -1
- package/dist/LlmService.d.ts +1 -2
- package/dist/LlmService.d.ts.map +1 -1
- package/dist/LlmService.js.map +1 -1
- package/dist/Models.d.ts +0 -21
- package/dist/Models.d.ts.map +1 -1
- package/dist/Models.js +0 -19
- package/dist/Models.js.map +1 -1
- package/dist/Streaming.d.ts +4 -11
- package/dist/Streaming.d.ts.map +1 -1
- package/dist/Streaming.js +2 -29
- package/dist/Streaming.js.map +1 -1
- package/dist/providers/AnthropicModels.d.ts +0 -43
- package/dist/providers/AnthropicModels.d.ts.map +1 -1
- package/dist/providers/AnthropicModels.js +0 -39
- package/dist/providers/AnthropicModels.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +2 -3
- package/dist/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/AnthropicProvider.js +2 -49
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/GeminiApiProvider.d.ts +2 -3
- package/dist/providers/GeminiApiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiApiProvider.js +2 -44
- package/dist/providers/GeminiApiProvider.js.map +1 -1
- package/dist/providers/GeminiModels.d.ts +0 -48
- package/dist/providers/GeminiModels.d.ts.map +1 -1
- package/dist/providers/GeminiModels.js +0 -40
- package/dist/providers/GeminiModels.js.map +1 -1
- package/dist/providers/LmStudioProvider.d.ts.map +1 -1
- package/dist/providers/LmStudioProvider.js +1 -4
- package/dist/providers/LmStudioProvider.js.map +1 -1
- package/dist/providers/MlxLmProvider.d.ts.map +1 -1
- package/dist/providers/MlxLmProvider.js +1 -2
- package/dist/providers/MlxLmProvider.js.map +1 -1
- package/dist/providers/MockProvider.d.ts.map +1 -1
- package/dist/providers/MockProvider.js +1 -6
- package/dist/providers/MockProvider.js.map +1 -1
- package/dist/providers/OllamaProvider.d.ts.map +1 -1
- package/dist/providers/OllamaProvider.js +1 -4
- package/dist/providers/OllamaProvider.js.map +1 -1
- package/dist/providers/OpenAIModels.d.ts +0 -58
- package/dist/providers/OpenAIModels.d.ts.map +1 -1
- package/dist/providers/OpenAIModels.js +0 -51
- package/dist/providers/OpenAIModels.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts +2 -3
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +2 -46
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/package.json +2 -14
- package/src/Capability.ts +0 -50
- package/src/Connector.ts +2 -20
- package/src/ConnectorRegistry.ts +0 -15
- package/src/HttpClient.ts +0 -15
- package/src/LlmService.ts +1 -13
- package/src/Models.ts +0 -22
- package/src/Streaming.ts +3 -99
- package/src/providers/AnthropicModels.ts +0 -47
- package/src/providers/AnthropicProvider.ts +1 -87
- package/src/providers/GeminiApiProvider.ts +2 -83
- package/src/providers/GeminiModels.ts +0 -46
- package/src/providers/LmStudioProvider.ts +1 -7
- package/src/providers/MlxLmProvider.ts +1 -3
- package/src/providers/MockProvider.ts +0 -9
- package/src/providers/OllamaProvider.ts +1 -7
- package/src/providers/OpenAIModels.ts +0 -64
- package/src/providers/OpenAIProvider.ts +2 -83
- package/dist/ContextManagement.d.ts +0 -78
- package/dist/ContextManagement.d.ts.map +0 -1
- package/dist/ContextManagement.js +0 -222
- package/dist/ContextManagement.js.map +0 -1
- package/dist/Conversation.d.ts +0 -18
- package/dist/Conversation.d.ts.map +0 -1
- package/dist/Conversation.js +0 -17
- package/dist/Conversation.js.map +0 -1
- package/dist/RateLimiter.d.ts +0 -44
- package/dist/RateLimiter.d.ts.map +0 -1
- package/dist/RateLimiter.js +0 -155
- package/dist/RateLimiter.js.map +0 -1
- package/dist/observability/MeteredLlmService.d.ts +0 -16
- package/dist/observability/MeteredLlmService.d.ts.map +0 -1
- package/dist/observability/MeteredLlmService.js +0 -72
- package/dist/observability/MeteredLlmService.js.map +0 -1
- package/dist/observability/Metrics.d.ts +0 -76
- package/dist/observability/Metrics.d.ts.map +0 -1
- package/dist/observability/Metrics.js +0 -152
- package/dist/observability/Metrics.js.map +0 -1
- package/dist/observability/StructuredLogger.d.ts +0 -31
- package/dist/observability/StructuredLogger.d.ts.map +0 -1
- package/dist/observability/StructuredLogger.js +0 -39
- package/dist/observability/StructuredLogger.js.map +0 -1
- package/dist/observability/Tracing.d.ts +0 -38
- package/dist/observability/Tracing.d.ts.map +0 -1
- package/dist/observability/Tracing.js +0 -80
- package/dist/observability/Tracing.js.map +0 -1
- package/dist/providers/OpenCodeModels.d.ts +0 -61
- package/dist/providers/OpenCodeModels.d.ts.map +0 -1
- package/dist/providers/OpenCodeModels.js +0 -53
- package/dist/providers/OpenCodeModels.js.map +0 -1
- package/dist/providers/OpenCodeProvider.d.ts +0 -10
- package/dist/providers/OpenCodeProvider.d.ts.map +0 -1
- package/dist/providers/OpenCodeProvider.js +0 -154
- package/dist/providers/OpenCodeProvider.js.map +0 -1
- package/dist/tools/Tool.d.ts +0 -83
- package/dist/tools/Tool.d.ts.map +0 -1
- package/dist/tools/Tool.js +0 -278
- package/dist/tools/Tool.js.map +0 -1
- package/dist/tools/ToolCallingExecutor.d.ts +0 -18
- package/dist/tools/ToolCallingExecutor.d.ts.map +0 -1
- package/dist/tools/ToolCallingExecutor.js +0 -64
- package/dist/tools/ToolCallingExecutor.js.map +0 -1
- package/dist/tools/ToolRegistry.d.ts +0 -45
- package/dist/tools/ToolRegistry.d.ts.map +0 -1
- package/dist/tools/ToolRegistry.js +0 -133
- package/dist/tools/ToolRegistry.js.map +0 -1
- package/src/ContextManagement.ts +0 -367
- package/src/Conversation.ts +0 -21
- package/src/RateLimiter.ts +0 -238
- package/src/observability/MeteredLlmService.ts +0 -168
- package/src/observability/Metrics.ts +0 -200
- package/src/observability/StructuredLogger.ts +0 -67
- package/src/observability/Tracing.ts +0 -146
- package/src/providers/OpenCodeModels.ts +0 -60
- package/src/providers/OpenCodeProvider.ts +0 -278
- package/src/tools/Tool.ts +0 -376
- package/src/tools/ToolCallingExecutor.ts +0 -106
- package/src/tools/ToolRegistry.ts +0 -224
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated Since 2.30.0 (ADR 0026): llm4ts exports OpenTelemetry spans and
|
|
3
|
-
* metrics over OTLP from `@llm4ts/runner/Otel`; this in-memory module is not
|
|
4
|
-
* used by flow or runner and will be removed in the next major.
|
|
5
|
-
*/
|
|
6
|
-
import * as Clock from "effect/Clock"
|
|
7
|
-
import * as Context from "effect/Context"
|
|
8
|
-
import * as Effect from "effect/Effect"
|
|
9
|
-
import * as Exit from "effect/Exit"
|
|
10
|
-
import * as Layer from "effect/Layer"
|
|
11
|
-
import * as Ref from "effect/Ref"
|
|
12
|
-
import * as Schema from "effect/Schema"
|
|
13
|
-
import type { JsonValue } from "../providers/CliSupport.ts"
|
|
14
|
-
import { redactText, sanitizeFields, type RedactionOptions } from "./Redaction.ts"
|
|
15
|
-
|
|
16
|
-
export const TraceStatus = Schema.Literals(["Ok", "Error"])
|
|
17
|
-
export type TraceStatus = typeof TraceStatus.Type
|
|
18
|
-
|
|
19
|
-
export class TraceSpan extends Schema.Class<TraceSpan>("TraceSpan")({
|
|
20
|
-
traceId: Schema.String,
|
|
21
|
-
spanId: Schema.String,
|
|
22
|
-
parentSpanId: Schema.optionalKey(Schema.String),
|
|
23
|
-
correlationId: Schema.String,
|
|
24
|
-
name: Schema.String,
|
|
25
|
-
status: TraceStatus,
|
|
26
|
-
startedAt: Schema.Number,
|
|
27
|
-
endedAt: Schema.Number,
|
|
28
|
-
attributes: Schema.Record(Schema.String, Schema.Json),
|
|
29
|
-
errorMessage: Schema.optionalKey(Schema.String)
|
|
30
|
-
}) {}
|
|
31
|
-
|
|
32
|
-
interface TraceContext {
|
|
33
|
-
readonly traceId: string
|
|
34
|
-
readonly spanId: string
|
|
35
|
-
readonly correlationId: string
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const CurrentTraceContext = Context.Reference<TraceContext | undefined>(
|
|
39
|
-
"@llm4ts/core/observability/CurrentTraceContext",
|
|
40
|
-
{ defaultValue: () => undefined }
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
export interface TracingServiceShape {
|
|
44
|
-
readonly withCorrelationId: <A, E, R>(
|
|
45
|
-
id: string,
|
|
46
|
-
effect: Effect.Effect<A, E, R>
|
|
47
|
-
) => Effect.Effect<A, E, R>
|
|
48
|
-
readonly correlationId: Effect.Effect<string>
|
|
49
|
-
readonly inSpan: <A, E, R>(
|
|
50
|
-
name: string,
|
|
51
|
-
attributes: Readonly<Record<string, JsonValue>>,
|
|
52
|
-
effect: Effect.Effect<A, E, R>
|
|
53
|
-
) => Effect.Effect<A, E, R>
|
|
54
|
-
readonly recordedSpans: Effect.Effect<ReadonlyArray<TraceSpan>>
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export class TracingService extends Context.Service<TracingService, TracingServiceShape>()(
|
|
58
|
-
"@llm4ts/core/observability/TracingService"
|
|
59
|
-
) {}
|
|
60
|
-
|
|
61
|
-
export interface TracingOptions extends RedactionOptions {
|
|
62
|
-
readonly makeId?: Effect.Effect<string>
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const defaultId = Effect.sync(() => globalThis.crypto.randomUUID())
|
|
66
|
-
|
|
67
|
-
export const makeTracingService = Effect.fn("@llm4ts/core/observability/TracingService.make")(
|
|
68
|
-
function* (options: TracingOptions = {}): Effect.fn.Return<TracingServiceShape> {
|
|
69
|
-
const spans = yield* Ref.make<ReadonlyArray<TraceSpan>>([])
|
|
70
|
-
const makeId = options.makeId ?? defaultId
|
|
71
|
-
|
|
72
|
-
const correlationId = Effect.flatMap(CurrentTraceContext, (current) =>
|
|
73
|
-
current === undefined ? makeId : Effect.succeed(current.correlationId)
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
const withCorrelationId = <A, E, R>(
|
|
77
|
-
id: string,
|
|
78
|
-
effect: Effect.Effect<A, E, R>
|
|
79
|
-
): Effect.Effect<A, E, R> =>
|
|
80
|
-
Effect.flatMap(CurrentTraceContext, (current) =>
|
|
81
|
-
Effect.provideService(effect, CurrentTraceContext, {
|
|
82
|
-
traceId: current?.traceId ?? id,
|
|
83
|
-
spanId: current?.spanId ?? id,
|
|
84
|
-
correlationId: id
|
|
85
|
-
})
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
const inSpan = <A, E, R>(
|
|
89
|
-
name: string,
|
|
90
|
-
attributes: Readonly<Record<string, JsonValue>>,
|
|
91
|
-
effect: Effect.Effect<A, E, R>
|
|
92
|
-
): Effect.Effect<A, E, R> =>
|
|
93
|
-
Effect.gen(function* () {
|
|
94
|
-
const parent = yield* CurrentTraceContext
|
|
95
|
-
const correlation = yield* correlationId
|
|
96
|
-
const traceId = parent?.traceId ?? (yield* makeId)
|
|
97
|
-
const spanId = yield* makeId
|
|
98
|
-
const startedAt = yield* Clock.currentTimeMillis
|
|
99
|
-
const next: TraceContext = {
|
|
100
|
-
traceId,
|
|
101
|
-
spanId,
|
|
102
|
-
correlationId: correlation
|
|
103
|
-
}
|
|
104
|
-
return yield* Effect.provideService(
|
|
105
|
-
effect.pipe(
|
|
106
|
-
Effect.onExit((exit) =>
|
|
107
|
-
Clock.currentTimeMillis.pipe(
|
|
108
|
-
Effect.flatMap((endedAt) =>
|
|
109
|
-
Ref.update(spans, (current) => [
|
|
110
|
-
...current,
|
|
111
|
-
TraceSpan.make({
|
|
112
|
-
traceId,
|
|
113
|
-
spanId,
|
|
114
|
-
...(parent === undefined ? {} : { parentSpanId: parent.spanId }),
|
|
115
|
-
correlationId: correlation,
|
|
116
|
-
name,
|
|
117
|
-
status: Exit.isSuccess(exit) ? "Ok" : "Error",
|
|
118
|
-
startedAt,
|
|
119
|
-
endedAt,
|
|
120
|
-
attributes: sanitizeFields(attributes, options),
|
|
121
|
-
...(Exit.isFailure(exit)
|
|
122
|
-
? {
|
|
123
|
-
errorMessage: redactText(String(exit.cause), options)
|
|
124
|
-
}
|
|
125
|
-
: {})
|
|
126
|
-
})
|
|
127
|
-
])
|
|
128
|
-
)
|
|
129
|
-
)
|
|
130
|
-
)
|
|
131
|
-
),
|
|
132
|
-
CurrentTraceContext,
|
|
133
|
-
next
|
|
134
|
-
)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
withCorrelationId,
|
|
139
|
-
correlationId,
|
|
140
|
-
inSpan,
|
|
141
|
-
recordedSpans: Ref.get(spans)
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
export const TracingServiceLive = Layer.effect(TracingService, makeTracingService())
|
|
@@ -1,60 +0,0 @@
|
|
|
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
|
-
}) {}
|
|
@@ -1,278 +0,0 @@
|
|
|
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 {
|
|
7
|
-
AuthenticationError,
|
|
8
|
-
ConfigError,
|
|
9
|
-
InvalidRequestError,
|
|
10
|
-
ParseError,
|
|
11
|
-
type LlmError
|
|
12
|
-
} from "../Errors.ts"
|
|
13
|
-
import type { HttpClientShape } from "../HttpClient.ts"
|
|
14
|
-
import type { StructuredResult } from "../LlmService.ts"
|
|
15
|
-
import {
|
|
16
|
-
ConnectorIds,
|
|
17
|
-
LlmChunk,
|
|
18
|
-
TokenUsage,
|
|
19
|
-
type JsonSchema,
|
|
20
|
-
type LlmConfig,
|
|
21
|
-
type Message,
|
|
22
|
-
type MessageRole
|
|
23
|
-
} from "../Models.ts"
|
|
24
|
-
import { parseFromText } from "../StructuredOutput.ts"
|
|
25
|
-
import {
|
|
26
|
-
OpenCodeCompletionRequest,
|
|
27
|
-
OpenCodeCompletionResponse,
|
|
28
|
-
OpenCodeJsonSchemaSpec,
|
|
29
|
-
OpenCodeMessage,
|
|
30
|
-
OpenCodeResponseFormat
|
|
31
|
-
} from "./OpenCodeModels.ts"
|
|
32
|
-
|
|
33
|
-
interface OpenCodeRequiredConfig {
|
|
34
|
-
readonly baseUrl: string
|
|
35
|
-
readonly apiKey: string
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const roleName = (role: MessageRole): string => {
|
|
39
|
-
switch (role) {
|
|
40
|
-
case "System":
|
|
41
|
-
return "system"
|
|
42
|
-
case "User":
|
|
43
|
-
return "user"
|
|
44
|
-
case "Assistant":
|
|
45
|
-
return "assistant"
|
|
46
|
-
case "Tool":
|
|
47
|
-
return "tool"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const openCodeHistory = (messages: ReadonlyArray<Message>): ReadonlyArray<OpenCodeMessage> =>
|
|
52
|
-
messages.map((message) =>
|
|
53
|
-
OpenCodeMessage.make({
|
|
54
|
-
role: roleName(message.role),
|
|
55
|
-
content: message.content
|
|
56
|
-
})
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
const usage = (response: OpenCodeCompletionResponse): TokenUsage | undefined =>
|
|
60
|
-
response.usage === undefined
|
|
61
|
-
? undefined
|
|
62
|
-
: TokenUsage.make({
|
|
63
|
-
prompt: response.usage.prompt_tokens ?? 0,
|
|
64
|
-
completion: response.usage.completion_tokens ?? 0,
|
|
65
|
-
total: response.usage.total_tokens ?? 0
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
const metadata = (
|
|
69
|
-
config: LlmConfig,
|
|
70
|
-
response: OpenCodeCompletionResponse
|
|
71
|
-
): Readonly<Record<string, string>> => ({
|
|
72
|
-
provider: "opencode",
|
|
73
|
-
model: config.model,
|
|
74
|
-
...(response.id === undefined ? {} : { id: response.id }),
|
|
75
|
-
...(response.model === undefined ? {} : { response_model: response.model })
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const decodeResponse = (
|
|
79
|
-
raw: string,
|
|
80
|
-
context: string
|
|
81
|
-
): Effect.Effect<OpenCodeCompletionResponse, ParseError> =>
|
|
82
|
-
Schema.decodeUnknownEffect(Schema.fromJsonString(OpenCodeCompletionResponse))(raw).pipe(
|
|
83
|
-
Effect.mapError((error) =>
|
|
84
|
-
ParseError.make({
|
|
85
|
-
message: `${context}: ${String(error)}`,
|
|
86
|
-
raw
|
|
87
|
-
})
|
|
88
|
-
)
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
const toChunk = (config: LlmConfig, response: OpenCodeCompletionResponse): LlmChunk => {
|
|
92
|
-
const choice = response.choices[0]
|
|
93
|
-
const delta = choice?.delta?.content ?? choice?.message?.content ?? choice?.text ?? ""
|
|
94
|
-
const finishReason = choice?.finish_reason ?? undefined
|
|
95
|
-
const tokenUsage = usage(response)
|
|
96
|
-
return LlmChunk.make({
|
|
97
|
-
delta,
|
|
98
|
-
metadata: metadata(config, response),
|
|
99
|
-
...(finishReason === undefined || finishReason === null ? {} : { finishReason }),
|
|
100
|
-
...(tokenUsage === undefined ? {} : { usage: tokenUsage })
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export const parseOpenCodeSseBody = Effect.fn("@llm4ts/core/OpenCodeProvider.parseSseBody")(
|
|
105
|
-
function* (config: LlmConfig, raw: string): Effect.fn.Return<ReadonlyArray<LlmChunk>, LlmError> {
|
|
106
|
-
const payloads = raw
|
|
107
|
-
.split(/\r?\n/)
|
|
108
|
-
.map((line) => line.trim())
|
|
109
|
-
.filter((line) => line.startsWith("data:"))
|
|
110
|
-
.map((line) => line.slice("data:".length).trim())
|
|
111
|
-
.filter((payload) => payload.length > 0 && payload !== "[DONE]")
|
|
112
|
-
const chunks = yield* Effect.forEach(payloads, (payload) =>
|
|
113
|
-
Effect.map(decodeResponse(payload, "Failed to parse OpenCode SSE payload"), (response) =>
|
|
114
|
-
toChunk(config, response)
|
|
115
|
-
)
|
|
116
|
-
)
|
|
117
|
-
return chunks.length === 0
|
|
118
|
-
? yield* Effect.fail(
|
|
119
|
-
ParseError.make({
|
|
120
|
-
message: "No stream chunks parsed from OpenCode SSE response",
|
|
121
|
-
raw
|
|
122
|
-
})
|
|
123
|
-
)
|
|
124
|
-
: chunks
|
|
125
|
-
}
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
export const makeOpenCodeProvider = (
|
|
129
|
-
config: LlmConfig,
|
|
130
|
-
httpClient: HttpClientShape
|
|
131
|
-
): ApiConnectorShape => {
|
|
132
|
-
const requiredConfig: Effect.Effect<OpenCodeRequiredConfig, LlmError> =
|
|
133
|
-
config.baseUrl === undefined
|
|
134
|
-
? Effect.fail(
|
|
135
|
-
ConfigError.make({
|
|
136
|
-
message: "Missing baseUrl for OpenCode provider"
|
|
137
|
-
})
|
|
138
|
-
)
|
|
139
|
-
: config.apiKey === undefined
|
|
140
|
-
? Effect.fail(
|
|
141
|
-
AuthenticationError.make({
|
|
142
|
-
message: "Missing API key for OpenCode provider (pass apiKey in the connector config)"
|
|
143
|
-
})
|
|
144
|
-
)
|
|
145
|
-
: Effect.succeed({
|
|
146
|
-
baseUrl: config.baseUrl.replace(/\/+$/, ""),
|
|
147
|
-
apiKey: Redacted.value(config.apiKey)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
const request = (
|
|
151
|
-
messages: ReadonlyArray<OpenCodeMessage>,
|
|
152
|
-
stream: boolean,
|
|
153
|
-
responseFormat?: OpenCodeResponseFormat
|
|
154
|
-
): OpenCodeCompletionRequest =>
|
|
155
|
-
OpenCodeCompletionRequest.make({
|
|
156
|
-
model: config.model,
|
|
157
|
-
messages,
|
|
158
|
-
temperature: config.temperature ?? 0.7,
|
|
159
|
-
stream,
|
|
160
|
-
...(config.maxTokens === undefined ? {} : { max_tokens: config.maxTokens }),
|
|
161
|
-
...(responseFormat === undefined ? {} : { response_format: responseFormat })
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
const post = (
|
|
165
|
-
messages: ReadonlyArray<OpenCodeMessage>,
|
|
166
|
-
stream: boolean,
|
|
167
|
-
responseFormat?: OpenCodeResponseFormat
|
|
168
|
-
): Effect.Effect<string, LlmError> =>
|
|
169
|
-
Effect.flatMap(requiredConfig, ({ apiKey, baseUrl }) =>
|
|
170
|
-
httpClient.postJson(
|
|
171
|
-
`${baseUrl}/chat/completions`,
|
|
172
|
-
JSON.stringify(request(messages, stream, responseFormat)),
|
|
173
|
-
{
|
|
174
|
-
Authorization: `Bearer ${apiKey}`
|
|
175
|
-
},
|
|
176
|
-
config.timeout
|
|
177
|
-
)
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
const executeResponse = (
|
|
181
|
-
messages: ReadonlyArray<OpenCodeMessage>,
|
|
182
|
-
responseFormat?: OpenCodeResponseFormat
|
|
183
|
-
): Effect.Effect<readonly [response: OpenCodeCompletionResponse, raw: string], LlmError> =>
|
|
184
|
-
Effect.gen(function* () {
|
|
185
|
-
const raw = yield* post(messages, false, responseFormat)
|
|
186
|
-
const response = yield* decodeResponse(raw, "Failed to decode OpenCode response")
|
|
187
|
-
return [response, raw]
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
const responseContent = (
|
|
191
|
-
response: OpenCodeCompletionResponse,
|
|
192
|
-
raw: string
|
|
193
|
-
): Effect.Effect<string, ParseError> => {
|
|
194
|
-
const content = (response.choices[0]?.message?.content ?? response.choices[0]?.text)?.trim()
|
|
195
|
-
return content === undefined || content === null || content.length === 0
|
|
196
|
-
? Effect.fail(
|
|
197
|
-
ParseError.make({
|
|
198
|
-
message: "OpenCode response missing choices[0].message.content",
|
|
199
|
-
raw
|
|
200
|
-
})
|
|
201
|
-
)
|
|
202
|
-
: Effect.succeed(content)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const executeStructuredWithUsage = <A, E, RD, RE>(
|
|
206
|
-
prompt: string,
|
|
207
|
-
schema: Schema.ConstraintCodec<A, E, RD, RE>,
|
|
208
|
-
jsonSchema: JsonSchema
|
|
209
|
-
): Effect.Effect<StructuredResult<A>, LlmError, RD> =>
|
|
210
|
-
Effect.gen(function* () {
|
|
211
|
-
const responseFormat = OpenCodeResponseFormat.make({
|
|
212
|
-
type: "json_schema",
|
|
213
|
-
json_schema: OpenCodeJsonSchemaSpec.make({
|
|
214
|
-
name: "response",
|
|
215
|
-
schema: jsonSchema
|
|
216
|
-
})
|
|
217
|
-
})
|
|
218
|
-
const [response, raw] = yield* executeResponse(
|
|
219
|
-
[
|
|
220
|
-
OpenCodeMessage.make({
|
|
221
|
-
role: "user",
|
|
222
|
-
content: prompt
|
|
223
|
-
})
|
|
224
|
-
],
|
|
225
|
-
responseFormat
|
|
226
|
-
)
|
|
227
|
-
const content = yield* responseContent(response, raw)
|
|
228
|
-
const value = yield* parseFromText(content, schema, jsonSchema)
|
|
229
|
-
const result: StructuredResult<A> = [value, undefined, undefined]
|
|
230
|
-
return result
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
const stream = (messages: ReadonlyArray<OpenCodeMessage>): Stream.Stream<LlmChunk, LlmError> =>
|
|
234
|
-
Stream.flatMap(
|
|
235
|
-
Stream.fromEffect(
|
|
236
|
-
Effect.flatMap(post(messages, true), (raw) => parseOpenCodeSseBody(config, raw))
|
|
237
|
-
),
|
|
238
|
-
Stream.fromIterable
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
const isAvailable: Effect.Effect<boolean> =
|
|
242
|
-
config.baseUrl === undefined || config.apiKey === undefined
|
|
243
|
-
? Effect.succeed(false)
|
|
244
|
-
: httpClient
|
|
245
|
-
.get(
|
|
246
|
-
`${config.baseUrl.replace(/\/+$/, "")}/models`,
|
|
247
|
-
{
|
|
248
|
-
Authorization: `Bearer ${Redacted.value(config.apiKey)}`
|
|
249
|
-
},
|
|
250
|
-
config.timeout
|
|
251
|
-
)
|
|
252
|
-
.pipe(
|
|
253
|
-
Effect.match({
|
|
254
|
-
onFailure: () => false,
|
|
255
|
-
onSuccess: () => true
|
|
256
|
-
})
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
return makeApiConnector({
|
|
260
|
-
id: ConnectorIds.OpenCode,
|
|
261
|
-
executeStream: (prompt) =>
|
|
262
|
-
stream([
|
|
263
|
-
OpenCodeMessage.make({
|
|
264
|
-
role: "user",
|
|
265
|
-
content: prompt
|
|
266
|
-
})
|
|
267
|
-
]),
|
|
268
|
-
executeStreamWithHistory: (messages) => stream(openCodeHistory(messages)),
|
|
269
|
-
executeWithTools: () =>
|
|
270
|
-
Effect.fail(
|
|
271
|
-
InvalidRequestError.make({
|
|
272
|
-
message: "OpenCode provider does not yet support tool calling in this implementation"
|
|
273
|
-
})
|
|
274
|
-
),
|
|
275
|
-
executeStructuredWithUsage,
|
|
276
|
-
isAvailable
|
|
277
|
-
})
|
|
278
|
-
}
|