effect 4.0.0-beta.32 → 4.0.0-beta.34
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/dist/Effect.d.ts +12 -6
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +4 -4
- package/dist/Effect.js.map +1 -1
- package/dist/FileSystem.d.ts.map +1 -1
- package/dist/FileSystem.js +2 -1
- package/dist/FileSystem.js.map +1 -1
- package/dist/Graph.d.ts.map +1 -1
- package/dist/Graph.js +2 -1
- package/dist/Graph.js.map +1 -1
- package/dist/MutableHashMap.d.ts +7 -0
- package/dist/MutableHashMap.d.ts.map +1 -1
- package/dist/MutableHashMap.js +8 -0
- package/dist/MutableHashMap.js.map +1 -1
- package/dist/MutableHashSet.d.ts +7 -0
- package/dist/MutableHashSet.d.ts.map +1 -1
- package/dist/MutableHashSet.js +8 -0
- package/dist/MutableHashSet.js.map +1 -1
- package/dist/Queue.d.ts +1 -1
- package/dist/Queue.d.ts.map +1 -1
- package/dist/Queue.js.map +1 -1
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +2 -1
- package/dist/Resource.js.map +1 -1
- package/dist/SubscriptionRef.d.ts.map +1 -1
- package/dist/SubscriptionRef.js +2 -1
- package/dist/SubscriptionRef.js.map +1 -1
- package/dist/TxDeferred.d.ts.map +1 -1
- package/dist/TxDeferred.js +2 -1
- package/dist/TxDeferred.js.map +1 -1
- package/dist/TxHashMap.d.ts.map +1 -1
- package/dist/TxHashMap.js +2 -1
- package/dist/TxHashMap.js.map +1 -1
- package/dist/TxHashSet.d.ts +1 -1
- package/dist/TxHashSet.d.ts.map +1 -1
- package/dist/TxHashSet.js +2 -1
- package/dist/TxHashSet.js.map +1 -1
- package/dist/TxPriorityQueue.d.ts +1 -1
- package/dist/TxPriorityQueue.d.ts.map +1 -1
- package/dist/TxPriorityQueue.js +2 -1
- package/dist/TxPriorityQueue.js.map +1 -1
- package/dist/TxSemaphore.d.ts.map +1 -1
- package/dist/TxSemaphore.js +2 -1
- package/dist/TxSemaphore.js.map +1 -1
- package/dist/internal/effect.js +1 -1
- package/dist/internal/effect.js.map +1 -1
- package/dist/unstable/ai/AiError.d.ts +1 -3
- package/dist/unstable/ai/AiError.d.ts.map +1 -1
- package/dist/unstable/ai/AiError.js +1 -3
- package/dist/unstable/ai/AiError.js.map +1 -1
- package/dist/unstable/ai/EmbeddingModel.d.ts +130 -0
- package/dist/unstable/ai/EmbeddingModel.d.ts.map +1 -0
- package/dist/unstable/ai/EmbeddingModel.js +127 -0
- package/dist/unstable/ai/EmbeddingModel.js.map +1 -0
- package/dist/unstable/ai/LanguageModel.d.ts +8 -0
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +127 -16
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/ai/ResponseIdTracker.d.ts +38 -0
- package/dist/unstable/ai/ResponseIdTracker.d.ts.map +1 -0
- package/dist/unstable/ai/ResponseIdTracker.js +68 -0
- package/dist/unstable/ai/ResponseIdTracker.js.map +1 -0
- package/dist/unstable/ai/Tool.d.ts +1 -1
- package/dist/unstable/ai/Tool.d.ts.map +1 -1
- package/dist/unstable/ai/Tool.js +1 -1
- package/dist/unstable/ai/Tool.js.map +1 -1
- package/dist/unstable/ai/index.d.ts +21 -0
- package/dist/unstable/ai/index.d.ts.map +1 -1
- package/dist/unstable/ai/index.js +21 -0
- package/dist/unstable/ai/index.js.map +1 -1
- package/dist/unstable/http/Url.d.ts +604 -0
- package/dist/unstable/http/Url.d.ts.map +1 -0
- package/dist/unstable/http/Url.js +256 -0
- package/dist/unstable/http/Url.js.map +1 -0
- package/dist/unstable/http/index.d.ts +4 -0
- package/dist/unstable/http/index.d.ts.map +1 -1
- package/dist/unstable/http/index.js +4 -0
- package/dist/unstable/http/index.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiMiddleware.d.ts +30 -1
- package/dist/unstable/httpapi/HttpApiMiddleware.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiMiddleware.js +27 -0
- package/dist/unstable/httpapi/HttpApiMiddleware.js.map +1 -1
- package/dist/unstable/socket/Socket.d.ts +2 -1
- package/dist/unstable/socket/Socket.d.ts.map +1 -1
- package/dist/unstable/socket/Socket.js +3 -2
- package/dist/unstable/socket/Socket.js.map +1 -1
- package/package.json +1 -1
- package/src/Effect.ts +16 -25
- package/src/FileSystem.ts +2 -1
- package/src/Graph.ts +2 -1
- package/src/MutableHashMap.ts +9 -0
- package/src/MutableHashSet.ts +9 -0
- package/src/Queue.ts +1 -1
- package/src/Resource.ts +2 -1
- package/src/SubscriptionRef.ts +2 -1
- package/src/TxDeferred.ts +2 -2
- package/src/TxHashMap.ts +2 -1
- package/src/TxHashSet.ts +2 -2
- package/src/TxPriorityQueue.ts +2 -3
- package/src/TxSemaphore.ts +2 -1
- package/src/internal/effect.ts +11 -4
- package/src/unstable/ai/AiError.ts +1 -3
- package/src/unstable/ai/EmbeddingModel.ts +209 -0
- package/src/unstable/ai/LanguageModel.ts +228 -69
- package/src/unstable/ai/ResponseIdTracker.ts +97 -0
- package/src/unstable/ai/Tool.ts +2 -2
- package/src/unstable/ai/index.ts +23 -0
- package/src/unstable/http/Url.ts +650 -0
- package/src/unstable/http/index.ts +5 -0
- package/src/unstable/httpapi/HttpApiMiddleware.ts +46 -1
- package/src/unstable/socket/Socket.ts +12 -8
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
import type * as Cause from "../../Cause.ts"
|
|
52
52
|
import * as Effect from "../../Effect.ts"
|
|
53
53
|
import * as FiberSet from "../../FiberSet.ts"
|
|
54
|
-
import { constFalse } from "../../Function.ts"
|
|
54
|
+
import { constFalse, identity, pipe } from "../../Function.ts"
|
|
55
55
|
import type * as JsonSchema from "../../JsonSchema.ts"
|
|
56
56
|
import * as Option from "../../Option.ts"
|
|
57
57
|
import * as Predicate from "../../Predicate.ts"
|
|
@@ -69,6 +69,7 @@ import { defaultIdGenerator, IdGenerator } from "./IdGenerator.ts"
|
|
|
69
69
|
import * as InternalCodecTransformer from "./internal/codec-transformer.ts"
|
|
70
70
|
import * as Prompt from "./Prompt.ts"
|
|
71
71
|
import * as Response from "./Response.ts"
|
|
72
|
+
import * as ResponseIdTracker from "./ResponseIdTracker.ts"
|
|
72
73
|
import type { SpanTransformer } from "./Telemetry.ts"
|
|
73
74
|
import { CurrentSpanTransformer } from "./Telemetry.ts"
|
|
74
75
|
import type * as Tool from "./Tool.ts"
|
|
@@ -648,6 +649,16 @@ export interface ProviderOptions {
|
|
|
648
649
|
* The span to use to trace interactions with the large language model.
|
|
649
650
|
*/
|
|
650
651
|
readonly span: Span
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* The previous response identifier for incremental provider calls.
|
|
655
|
+
*/
|
|
656
|
+
readonly previousResponseId: string | undefined
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* The prompt reduced to messages not yet seen by the provider.
|
|
660
|
+
*/
|
|
661
|
+
readonly incrementalPrompt: Prompt.Prompt | undefined
|
|
651
662
|
}
|
|
652
663
|
|
|
653
664
|
/**
|
|
@@ -727,7 +738,9 @@ export const make: (params: {
|
|
|
727
738
|
tools: [],
|
|
728
739
|
toolChoice: "none",
|
|
729
740
|
responseFormat: { type: "text" },
|
|
730
|
-
span
|
|
741
|
+
span,
|
|
742
|
+
previousResponseId: undefined,
|
|
743
|
+
incrementalPrompt: undefined
|
|
731
744
|
}
|
|
732
745
|
const content = yield* generateContent(options, providerOptions)
|
|
733
746
|
|
|
@@ -790,7 +803,9 @@ export const make: (params: {
|
|
|
790
803
|
objectName,
|
|
791
804
|
schema: options.schema
|
|
792
805
|
},
|
|
793
|
-
span
|
|
806
|
+
span,
|
|
807
|
+
previousResponseId: undefined,
|
|
808
|
+
incrementalPrompt: undefined
|
|
794
809
|
}
|
|
795
810
|
|
|
796
811
|
const content = yield* generateContent(options, providerOptions)
|
|
@@ -857,7 +872,9 @@ export const make: (params: {
|
|
|
857
872
|
tools: [],
|
|
858
873
|
toolChoice: "none",
|
|
859
874
|
responseFormat: { type: "text" },
|
|
860
|
-
span
|
|
875
|
+
span,
|
|
876
|
+
previousResponseId: undefined,
|
|
877
|
+
incrementalPrompt: undefined
|
|
861
878
|
}
|
|
862
879
|
|
|
863
880
|
// Resolve the content stream for the request
|
|
@@ -917,8 +934,23 @@ export const make: (params: {
|
|
|
917
934
|
options: Options & GenerateTextOptions<Tools>,
|
|
918
935
|
providerOptions: Mutable<ProviderOptions>
|
|
919
936
|
) {
|
|
937
|
+
const tracker = Option.getOrUndefined(yield* Effect.serviceOption(ResponseIdTracker.ResponseIdTracker))
|
|
920
938
|
const toolChoice = options.toolChoice ?? "auto"
|
|
921
939
|
|
|
940
|
+
const withNonIncrementalFallback = <R>(
|
|
941
|
+
effect: Effect.Effect<Array<Response.PartEncoded>, AiError.AiError, R>
|
|
942
|
+
): Effect.Effect<Array<Response.PartEncoded>, AiError.AiError, R | IdGenerator> =>
|
|
943
|
+
providerOptions.incrementalPrompt ?
|
|
944
|
+
effect.pipe(
|
|
945
|
+
Effect.catchReason("AiError", "InvalidRequestError", (_) =>
|
|
946
|
+
params.generateText({
|
|
947
|
+
...providerOptions,
|
|
948
|
+
incrementalPrompt: undefined,
|
|
949
|
+
previousResponseId: undefined
|
|
950
|
+
}))
|
|
951
|
+
) :
|
|
952
|
+
effect
|
|
953
|
+
|
|
922
954
|
// Check for pending approvals that need resolution
|
|
923
955
|
const { approved, denied } = collectToolApprovals(
|
|
924
956
|
providerOptions.prompt.content,
|
|
@@ -940,11 +972,24 @@ export const make: (params: {
|
|
|
940
972
|
})
|
|
941
973
|
})
|
|
942
974
|
}
|
|
975
|
+
if (tracker) {
|
|
976
|
+
const prepared = tracker.prepareUnsafe(providerOptions.prompt)
|
|
977
|
+
if (Option.isSome(prepared)) {
|
|
978
|
+
providerOptions.previousResponseId = prepared.value.previousResponseId
|
|
979
|
+
providerOptions.incrementalPrompt = prepared.value.prompt
|
|
980
|
+
}
|
|
981
|
+
}
|
|
943
982
|
const ResponseSchema = Schema.mutable(
|
|
944
983
|
Schema.Array(Response.Part(Toolkit.empty))
|
|
945
984
|
)
|
|
946
|
-
const rawContent = yield* params.generateText(providerOptions)
|
|
985
|
+
const rawContent = yield* withNonIncrementalFallback(params.generateText(providerOptions))
|
|
947
986
|
const content = yield* Schema.decodeEffect(ResponseSchema)(rawContent)
|
|
987
|
+
if (tracker) {
|
|
988
|
+
const responseMetadata = content.find((part) => part.type === "response-metadata")
|
|
989
|
+
if (Predicate.isNotUndefined(responseMetadata) && Predicate.isNotUndefined(responseMetadata.id)) {
|
|
990
|
+
tracker.markParts(providerOptions.prompt.content, responseMetadata.id)
|
|
991
|
+
}
|
|
992
|
+
}
|
|
948
993
|
return content as Array<Response.Part<Tools>>
|
|
949
994
|
}
|
|
950
995
|
|
|
@@ -965,11 +1010,24 @@ export const make: (params: {
|
|
|
965
1010
|
})
|
|
966
1011
|
})
|
|
967
1012
|
}
|
|
1013
|
+
if (tracker) {
|
|
1014
|
+
const prepared = tracker.prepareUnsafe(providerOptions.prompt)
|
|
1015
|
+
if (Option.isSome(prepared)) {
|
|
1016
|
+
providerOptions.previousResponseId = prepared.value.previousResponseId
|
|
1017
|
+
providerOptions.incrementalPrompt = prepared.value.prompt
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
968
1020
|
const ResponseSchema = Schema.mutable(
|
|
969
1021
|
Schema.Array(Response.Part(Toolkit.empty))
|
|
970
1022
|
)
|
|
971
|
-
const rawContent = yield* params.generateText(providerOptions)
|
|
1023
|
+
const rawContent = yield* withNonIncrementalFallback(params.generateText(providerOptions))
|
|
972
1024
|
const content = yield* Schema.decodeEffect(ResponseSchema)(rawContent)
|
|
1025
|
+
if (tracker) {
|
|
1026
|
+
const responseMetadata = content.find((part) => part.type === "response-metadata")
|
|
1027
|
+
if (Predicate.isNotUndefined(responseMetadata) && Predicate.isNotUndefined(responseMetadata.id)) {
|
|
1028
|
+
tracker.markParts(providerOptions.prompt.content, responseMetadata.id)
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
973
1031
|
return content as Array<Response.Part<Tools>>
|
|
974
1032
|
}
|
|
975
1033
|
|
|
@@ -1025,6 +1083,14 @@ export const make: (params: {
|
|
|
1025
1083
|
providerOptions.tools = tools
|
|
1026
1084
|
providerOptions.toolChoice = toolChoice
|
|
1027
1085
|
|
|
1086
|
+
if (tracker) {
|
|
1087
|
+
const prepared = tracker.prepareUnsafe(providerOptions.prompt)
|
|
1088
|
+
if (Option.isSome(prepared)) {
|
|
1089
|
+
providerOptions.previousResponseId = prepared.value.previousResponseId
|
|
1090
|
+
providerOptions.incrementalPrompt = prepared.value.prompt
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1028
1094
|
// Construct the response schema with the tools from the toolkit
|
|
1029
1095
|
const ResponseSchema = Schema.mutable(
|
|
1030
1096
|
Schema.Array(Response.Part(toolkit))
|
|
@@ -1033,12 +1099,18 @@ export const make: (params: {
|
|
|
1033
1099
|
// If tool call resolution is disabled, return the response without
|
|
1034
1100
|
// resolving the tool calls that were generated
|
|
1035
1101
|
if (options.disableToolCallResolution === true) {
|
|
1036
|
-
const rawContent = yield* params.generateText(providerOptions)
|
|
1102
|
+
const rawContent = yield* withNonIncrementalFallback(params.generateText(providerOptions))
|
|
1037
1103
|
const content = yield* Schema.decodeEffect(ResponseSchema)(rawContent)
|
|
1104
|
+
if (tracker) {
|
|
1105
|
+
const responseMetadata = content.find((part) => part.type === "response-metadata")
|
|
1106
|
+
if (Predicate.isNotUndefined(responseMetadata) && Predicate.isNotUndefined(responseMetadata.id)) {
|
|
1107
|
+
tracker.markParts(providerOptions.prompt.content, responseMetadata.id)
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1038
1110
|
return content as Array<Response.Part<Tools>>
|
|
1039
1111
|
}
|
|
1040
1112
|
|
|
1041
|
-
const rawContent = yield* params.generateText(providerOptions)
|
|
1113
|
+
const rawContent = yield* withNonIncrementalFallback(params.generateText(providerOptions))
|
|
1042
1114
|
|
|
1043
1115
|
// Resolve the generated tool calls
|
|
1044
1116
|
const toolResults = yield* resolveToolCalls(
|
|
@@ -1057,6 +1129,13 @@ export const make: (params: {
|
|
|
1057
1129
|
|
|
1058
1130
|
const content = yield* Schema.decodeEffect(ResponseSchema)(rawContent)
|
|
1059
1131
|
|
|
1132
|
+
if (tracker) {
|
|
1133
|
+
const responseMetadata = content.find((part) => part.type === "response-metadata")
|
|
1134
|
+
if (Predicate.isNotUndefined(responseMetadata) && Predicate.isNotUndefined(responseMetadata.id)) {
|
|
1135
|
+
tracker.markParts(providerOptions.prompt.content, responseMetadata.id)
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1060
1139
|
// Return the content merged with the tool call results
|
|
1061
1140
|
return [...content, ...toolResults] as Array<Response.Part<Tools>>
|
|
1062
1141
|
})
|
|
@@ -1086,8 +1165,23 @@ export const make: (params: {
|
|
|
1086
1165
|
options: Options & GenerateTextOptions<Tools>,
|
|
1087
1166
|
providerOptions: Mutable<ProviderOptions>
|
|
1088
1167
|
) {
|
|
1168
|
+
const tracker = Option.getOrUndefined(yield* Effect.serviceOption(ResponseIdTracker.ResponseIdTracker))
|
|
1089
1169
|
const toolChoice = options.toolChoice ?? "auto"
|
|
1090
1170
|
|
|
1171
|
+
const withNonIncrementalFallback = <R>(
|
|
1172
|
+
stream: Stream.Stream<Response.StreamPartEncoded, AiError.AiError, R>
|
|
1173
|
+
): Stream.Stream<Response.StreamPartEncoded, AiError.AiError, R | IdGenerator> =>
|
|
1174
|
+
providerOptions.incrementalPrompt ?
|
|
1175
|
+
stream.pipe(
|
|
1176
|
+
Stream.catchReason("AiError", "InvalidRequestError", (_) =>
|
|
1177
|
+
params.streamText({
|
|
1178
|
+
...providerOptions,
|
|
1179
|
+
incrementalPrompt: undefined,
|
|
1180
|
+
previousResponseId: undefined
|
|
1181
|
+
}))
|
|
1182
|
+
) :
|
|
1183
|
+
stream
|
|
1184
|
+
|
|
1091
1185
|
// Check for pending approvals that need resolution
|
|
1092
1186
|
const { approved: pendingApproved, denied: pendingDenied } = collectToolApprovals(providerOptions.prompt.content, {
|
|
1093
1187
|
excludeResolved: true
|
|
@@ -1108,17 +1202,37 @@ export const make: (params: {
|
|
|
1108
1202
|
})
|
|
1109
1203
|
})
|
|
1110
1204
|
}
|
|
1205
|
+
if (tracker) {
|
|
1206
|
+
const prepared = tracker.prepareUnsafe(providerOptions.prompt)
|
|
1207
|
+
if (Option.isSome(prepared)) {
|
|
1208
|
+
providerOptions.previousResponseId = prepared.value.previousResponseId
|
|
1209
|
+
providerOptions.incrementalPrompt = prepared.value.prompt
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1111
1212
|
const schema = Schema.NonEmptyArray(Response.StreamPart(Toolkit.empty))
|
|
1112
1213
|
const decodeParts = Schema.decodeEffect(schema)
|
|
1113
|
-
return
|
|
1114
|
-
.streamText(providerOptions)
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1214
|
+
return pipe(
|
|
1215
|
+
params.streamText(providerOptions),
|
|
1216
|
+
withNonIncrementalFallback,
|
|
1217
|
+
Stream.mapArrayEffect((parts) =>
|
|
1218
|
+
decodeParts(parts).pipe(
|
|
1219
|
+
tracker ?
|
|
1220
|
+
Effect.tap((decodedParts) => {
|
|
1221
|
+
for (const part of decodedParts) {
|
|
1222
|
+
if (part.type === "response-metadata" && Predicate.isNotUndefined(part.id)) {
|
|
1223
|
+
tracker.markParts(providerOptions.prompt.content, part.id)
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return Effect.void
|
|
1227
|
+
}) :
|
|
1228
|
+
identity
|
|
1229
|
+
)
|
|
1230
|
+
)
|
|
1231
|
+
) as Stream.Stream<
|
|
1232
|
+
Response.StreamPart<Tools>,
|
|
1233
|
+
AiError.AiError | Schema.SchemaError,
|
|
1234
|
+
IdGenerator
|
|
1235
|
+
>
|
|
1122
1236
|
}
|
|
1123
1237
|
|
|
1124
1238
|
// If there is a toolkit resolve and apply it to the provider options
|
|
@@ -1138,17 +1252,37 @@ export const make: (params: {
|
|
|
1138
1252
|
})
|
|
1139
1253
|
})
|
|
1140
1254
|
}
|
|
1255
|
+
if (tracker) {
|
|
1256
|
+
const prepared = tracker.prepareUnsafe(providerOptions.prompt)
|
|
1257
|
+
if (Option.isSome(prepared)) {
|
|
1258
|
+
providerOptions.previousResponseId = prepared.value.previousResponseId
|
|
1259
|
+
providerOptions.incrementalPrompt = prepared.value.prompt
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1141
1262
|
const schema = Schema.NonEmptyArray(Response.StreamPart(Toolkit.empty))
|
|
1142
1263
|
const decodeParts = Schema.decodeEffect(schema)
|
|
1143
|
-
return
|
|
1144
|
-
.streamText(providerOptions)
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1264
|
+
return pipe(
|
|
1265
|
+
params.streamText(providerOptions),
|
|
1266
|
+
withNonIncrementalFallback,
|
|
1267
|
+
Stream.mapArrayEffect((parts) =>
|
|
1268
|
+
decodeParts(parts).pipe(
|
|
1269
|
+
tracker ?
|
|
1270
|
+
Effect.tap((decodedParts) => {
|
|
1271
|
+
for (const part of decodedParts) {
|
|
1272
|
+
if (part.type === "response-metadata" && part.id) {
|
|
1273
|
+
tracker.markParts(providerOptions.prompt.content, part.id)
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return Effect.void
|
|
1277
|
+
}) :
|
|
1278
|
+
identity
|
|
1279
|
+
)
|
|
1280
|
+
)
|
|
1281
|
+
) as Stream.Stream<
|
|
1282
|
+
Response.StreamPart<Tools>,
|
|
1283
|
+
AiError.AiError | Schema.SchemaError,
|
|
1284
|
+
IdGenerator
|
|
1285
|
+
>
|
|
1152
1286
|
}
|
|
1153
1287
|
|
|
1154
1288
|
// Pre-resolve pending tool approvals before calling the LLM
|
|
@@ -1222,20 +1356,40 @@ export const make: (params: {
|
|
|
1222
1356
|
providerOptions.tools = tools
|
|
1223
1357
|
providerOptions.toolChoice = toolChoice
|
|
1224
1358
|
|
|
1359
|
+
if (tracker) {
|
|
1360
|
+
const prepared = tracker.prepareUnsafe(providerOptions.prompt)
|
|
1361
|
+
if (Option.isSome(prepared)) {
|
|
1362
|
+
providerOptions.previousResponseId = prepared.value.previousResponseId
|
|
1363
|
+
providerOptions.incrementalPrompt = prepared.value.prompt
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1225
1367
|
// If tool call resolution is disabled, return the response without
|
|
1226
1368
|
// resolving the tool calls that were generated
|
|
1227
1369
|
if (options.disableToolCallResolution === true) {
|
|
1228
1370
|
const schema = Schema.NonEmptyArray(Response.StreamPart(toolkit))
|
|
1229
1371
|
const decodeParts = Schema.decodeEffect(schema)
|
|
1230
|
-
return params
|
|
1231
|
-
|
|
1232
|
-
.
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1372
|
+
return params.streamText(providerOptions).pipe(
|
|
1373
|
+
withNonIncrementalFallback,
|
|
1374
|
+
Stream.mapArrayEffect((parts) =>
|
|
1375
|
+
decodeParts(parts).pipe(
|
|
1376
|
+
tracker ?
|
|
1377
|
+
Effect.tap((decodedParts) => {
|
|
1378
|
+
for (const part of decodedParts) {
|
|
1379
|
+
if (part.type === "response-metadata" && Predicate.isNotUndefined(part.id)) {
|
|
1380
|
+
tracker.markParts(providerOptions.prompt.content, part.id)
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
return Effect.void
|
|
1384
|
+
}) :
|
|
1385
|
+
identity
|
|
1386
|
+
)
|
|
1387
|
+
)
|
|
1388
|
+
) as Stream.Stream<
|
|
1389
|
+
Response.StreamPart<Tools>,
|
|
1390
|
+
AiError.AiError | Schema.SchemaError,
|
|
1391
|
+
IdGenerator
|
|
1392
|
+
>
|
|
1239
1393
|
}
|
|
1240
1394
|
|
|
1241
1395
|
const ResponseSchema = Schema.NonEmptyArray(Response.StreamPart(toolkit))
|
|
@@ -1260,48 +1414,53 @@ export const make: (params: {
|
|
|
1260
1414
|
const toolCallFibers = yield* FiberSet.make<void, AiError.AiError>()
|
|
1261
1415
|
|
|
1262
1416
|
// Helper function to handle tool calls with approval logic
|
|
1263
|
-
const handleToolCall = (part: Response.ToolCallPartEncoded)
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
if (!tool) {
|
|
1267
|
-
return
|
|
1268
|
-
}
|
|
1417
|
+
const handleToolCall = Effect.fnUntraced(function*(part: Response.ToolCallPartEncoded) {
|
|
1418
|
+
const tool = toolkit.tools[part.name]
|
|
1419
|
+
if (!tool) return
|
|
1269
1420
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1421
|
+
const needsApproval = yield* isApprovalNeeded(
|
|
1422
|
+
tool,
|
|
1423
|
+
part,
|
|
1424
|
+
providerOptions.prompt.content
|
|
1425
|
+
)
|
|
1275
1426
|
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1427
|
+
if (needsApproval) {
|
|
1428
|
+
const idGen = yield* IdGenerator
|
|
1429
|
+
const approvalId = yield* idGen.generateId()
|
|
1430
|
+
const approvalPart = Response.makePart("tool-approval-request", {
|
|
1431
|
+
approvalId,
|
|
1432
|
+
toolCallId: part.id
|
|
1433
|
+
}) as Response.StreamPart<Tools>
|
|
1434
|
+
yield* Queue.offer(queue, approvalPart)
|
|
1435
|
+
return
|
|
1436
|
+
}
|
|
1286
1437
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1438
|
+
yield* toolkit.handle(part.name, part.params as any).pipe(
|
|
1439
|
+
Stream.unwrap,
|
|
1440
|
+
Stream.runForEach((result) => {
|
|
1441
|
+
const toolResultPart = Response.makePart("tool-result", {
|
|
1442
|
+
id: part.id,
|
|
1443
|
+
name: part.name,
|
|
1444
|
+
providerExecuted: false,
|
|
1445
|
+
...result
|
|
1446
|
+
}) as Response.StreamPart<Tools>
|
|
1447
|
+
return Queue.offer(queue, toolResultPart)
|
|
1448
|
+
})
|
|
1449
|
+
)
|
|
1450
|
+
})
|
|
1300
1451
|
|
|
1301
1452
|
yield* params.streamText(providerOptions).pipe(
|
|
1453
|
+
withNonIncrementalFallback,
|
|
1302
1454
|
Stream.runForEachArray(
|
|
1303
1455
|
Effect.fnUntraced(function*(chunk) {
|
|
1304
1456
|
const parts = yield* decodeParts(chunk)
|
|
1457
|
+
if (tracker) {
|
|
1458
|
+
for (const part of parts) {
|
|
1459
|
+
if (part.type === "response-metadata" && part.id) {
|
|
1460
|
+
tracker.markParts(providerOptions.prompt.content, part.id)
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1305
1464
|
// Add decoded response parts to the output queue
|
|
1306
1465
|
yield* Queue.offerAll(queue, parts)
|
|
1307
1466
|
// Fork tool call handlers - use the raw chunk for encoded params
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 4.0.0
|
|
3
|
+
*/
|
|
4
|
+
import * as Effect from "../../Effect.ts"
|
|
5
|
+
import * as Option from "../../Option.ts"
|
|
6
|
+
import * as ServiceMap from "../../ServiceMap.ts"
|
|
7
|
+
import * as Prompt from "./Prompt.ts"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @since 4.0.0
|
|
11
|
+
* @category models
|
|
12
|
+
*/
|
|
13
|
+
export interface PrepareResult {
|
|
14
|
+
readonly previousResponseId: string
|
|
15
|
+
readonly prompt: Prompt.Prompt
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @since 4.0.0
|
|
20
|
+
* @category models
|
|
21
|
+
*/
|
|
22
|
+
export interface Service {
|
|
23
|
+
clearUnsafe(): void
|
|
24
|
+
markParts(parts: ReadonlyArray<object>, responseId: string): void
|
|
25
|
+
prepareUnsafe(prompt: Prompt.Prompt): Option.Option<PrepareResult>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @since 4.0.0
|
|
30
|
+
* @category Services
|
|
31
|
+
*/
|
|
32
|
+
export class ResponseIdTracker
|
|
33
|
+
extends ServiceMap.Service<ResponseIdTracker, Service>()("effect/ai/ResponseIdTracker")
|
|
34
|
+
{}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @since 4.0.0
|
|
38
|
+
* @category constructors
|
|
39
|
+
*/
|
|
40
|
+
export const make: Effect.Effect<Service> = Effect.sync(() => {
|
|
41
|
+
const sentParts = new Map<object, string>()
|
|
42
|
+
|
|
43
|
+
const none = () => {
|
|
44
|
+
sentParts.clear()
|
|
45
|
+
return Option.none<PrepareResult>()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
clearUnsafe() {
|
|
50
|
+
sentParts.clear()
|
|
51
|
+
},
|
|
52
|
+
markParts(parts, responseId) {
|
|
53
|
+
for (let i = 0; i < parts.length; i++) {
|
|
54
|
+
sentParts.set(parts[i], responseId)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
prepareUnsafe(prompt) {
|
|
58
|
+
const messages = prompt.content
|
|
59
|
+
|
|
60
|
+
let anyTracked = false
|
|
61
|
+
for (let i = 0; i < messages.length; i++) {
|
|
62
|
+
if (sentParts.has(messages[i])) {
|
|
63
|
+
anyTracked = true
|
|
64
|
+
break
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!anyTracked) return none()
|
|
68
|
+
|
|
69
|
+
let lastAssistantIndex = -1
|
|
70
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
71
|
+
if (messages[i].role === "assistant") {
|
|
72
|
+
lastAssistantIndex = i
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (lastAssistantIndex === -1) return none()
|
|
77
|
+
|
|
78
|
+
let responseId: string | undefined
|
|
79
|
+
for (let i = 0; i < lastAssistantIndex; i++) {
|
|
80
|
+
const id = sentParts.get(messages[i])
|
|
81
|
+
if (id === undefined) return none()
|
|
82
|
+
responseId = id
|
|
83
|
+
}
|
|
84
|
+
if (responseId === undefined) return none()
|
|
85
|
+
|
|
86
|
+
const partsAfterLastAssistant = messages.slice(lastAssistantIndex + 1)
|
|
87
|
+
if (partsAfterLastAssistant.length === 0) {
|
|
88
|
+
return none()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return Option.some({
|
|
92
|
+
previousResponseId: responseId,
|
|
93
|
+
prompt: Prompt.fromMessages(partsAfterLastAssistant)
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
})
|
package/src/unstable/ai/Tool.ts
CHANGED
|
@@ -1149,7 +1149,7 @@ const dynamicProto = <
|
|
|
1149
1149
|
*/
|
|
1150
1150
|
export const make = <
|
|
1151
1151
|
const Name extends string,
|
|
1152
|
-
Parameters extends Schema.Top = typeof
|
|
1152
|
+
Parameters extends Schema.Top = typeof EmptyParams,
|
|
1153
1153
|
Success extends Schema.Top = typeof Schema.Void,
|
|
1154
1154
|
Failure extends Schema.Top = typeof Schema.Never,
|
|
1155
1155
|
Mode extends FailureMode | undefined = undefined,
|
|
@@ -1210,7 +1210,7 @@ export const make = <
|
|
|
1210
1210
|
return userDefinedProto({
|
|
1211
1211
|
name,
|
|
1212
1212
|
description: options?.description,
|
|
1213
|
-
parametersSchema: options?.parameters ??
|
|
1213
|
+
parametersSchema: options?.parameters ?? EmptyParams,
|
|
1214
1214
|
successSchema,
|
|
1215
1215
|
failureSchema,
|
|
1216
1216
|
failureMode: options?.failureMode ?? "error",
|
package/src/unstable/ai/index.ts
CHANGED
|
@@ -153,6 +153,24 @@ export * as AnthropicStructuredOutput from "./AnthropicStructuredOutput.ts"
|
|
|
153
153
|
*/
|
|
154
154
|
export * as Chat from "./Chat.ts"
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* The `EmbeddingModel` module provides provider-agnostic text embedding capabilities.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* import { Effect } from "effect"
|
|
162
|
+
* import { EmbeddingModel } from "effect/unstable/ai"
|
|
163
|
+
*
|
|
164
|
+
* const program = Effect.gen(function*() {
|
|
165
|
+
* const model = yield* EmbeddingModel.EmbeddingModel
|
|
166
|
+
* return yield* model.embed("hello world")
|
|
167
|
+
* })
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @since 4.0.0
|
|
171
|
+
*/
|
|
172
|
+
export * as EmbeddingModel from "./EmbeddingModel.ts"
|
|
173
|
+
|
|
156
174
|
/**
|
|
157
175
|
* The `IdGenerator` module provides a pluggable system for generating unique identifiers
|
|
158
176
|
* for tool calls and other items in the Effect AI SDKs.
|
|
@@ -388,6 +406,11 @@ export * as Prompt from "./Prompt.ts"
|
|
|
388
406
|
*/
|
|
389
407
|
export * as Response from "./Response.ts"
|
|
390
408
|
|
|
409
|
+
/**
|
|
410
|
+
* @since 4.0.0
|
|
411
|
+
*/
|
|
412
|
+
export * as ResponseIdTracker from "./ResponseIdTracker.ts"
|
|
413
|
+
|
|
391
414
|
/**
|
|
392
415
|
* The `Telemetry` module provides OpenTelemetry integration for operations
|
|
393
416
|
* performed against a large language model provider by defining telemetry
|