effect 4.0.0-beta.11 → 4.0.0-beta.12
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/Config.d.ts +157 -0
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +56 -1
- package/dist/Config.js.map +1 -1
- package/dist/Effect.d.ts +79 -0
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +26 -0
- package/dist/Effect.js.map +1 -1
- package/dist/Fiber.d.ts +2 -2
- package/dist/Fiber.d.ts.map +1 -1
- package/dist/Fiber.js.map +1 -1
- package/dist/Graph.d.ts.map +1 -1
- package/dist/Graph.js +3 -6
- package/dist/Graph.js.map +1 -1
- package/dist/Random.d.ts +17 -0
- package/dist/Random.d.ts.map +1 -1
- package/dist/Random.js +17 -0
- package/dist/Random.js.map +1 -1
- package/dist/Schema.d.ts +3 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/internal/effect.js +59 -44
- package/dist/internal/effect.js.map +1 -1
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +49 -18
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/ai/McpSchema.d.ts +112 -36
- package/dist/unstable/ai/McpSchema.d.ts.map +1 -1
- package/dist/unstable/ai/McpSchema.js +47 -10
- package/dist/unstable/ai/McpSchema.js.map +1 -1
- package/dist/unstable/ai/McpServer.d.ts.map +1 -1
- package/dist/unstable/ai/McpServer.js +33 -6
- package/dist/unstable/ai/McpServer.js.map +1 -1
- package/dist/unstable/ai/Tool.d.ts +16 -0
- package/dist/unstable/ai/Tool.d.ts.map +1 -1
- package/dist/unstable/ai/Tool.js +14 -0
- package/dist/unstable/ai/Tool.js.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.js +2 -2
- package/dist/unstable/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/unstable/http/HttpClient.d.ts +28 -4
- package/dist/unstable/http/HttpClient.d.ts.map +1 -1
- package/dist/unstable/http/HttpClient.js.map +1 -1
- package/dist/unstable/http/HttpEffect.d.ts +3 -8
- package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
- package/dist/unstable/http/HttpEffect.js +13 -24
- package/dist/unstable/http/HttpEffect.js.map +1 -1
- package/dist/unstable/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/unstable/http/HttpMiddleware.js +4 -8
- package/dist/unstable/http/HttpMiddleware.js.map +1 -1
- package/dist/unstable/http/HttpServerError.d.ts +6 -1
- package/dist/unstable/http/HttpServerError.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerError.js +26 -17
- package/dist/unstable/http/HttpServerError.js.map +1 -1
- package/dist/unstable/http/internal/preResponseHandler.d.ts +2 -0
- package/dist/unstable/http/internal/preResponseHandler.d.ts.map +1 -0
- package/dist/unstable/http/internal/preResponseHandler.js +10 -0
- package/dist/unstable/http/internal/preResponseHandler.js.map +1 -0
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
- package/dist/unstable/reactivity/Atom.js +1 -1
- package/dist/unstable/reactivity/Atom.js.map +1 -1
- package/dist/unstable/rpc/RpcSchema.d.ts +13 -0
- package/dist/unstable/rpc/RpcSchema.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcSchema.js +14 -0
- package/dist/unstable/rpc/RpcSchema.js.map +1 -1
- package/dist/unstable/rpc/RpcSerialization.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcSerialization.js +34 -9
- package/dist/unstable/rpc/RpcSerialization.js.map +1 -1
- package/dist/unstable/rpc/RpcServer.d.ts +0 -7
- package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcServer.js +5 -10
- package/dist/unstable/rpc/RpcServer.js.map +1 -1
- package/package.json +1 -1
- package/src/Config.ts +171 -9
- package/src/Effect.ts +80 -0
- package/src/Fiber.ts +9 -2
- package/src/Graph.ts +16 -6
- package/src/Random.ts +18 -0
- package/src/Schema.ts +1 -1
- package/src/internal/effect.ts +82 -49
- package/src/unstable/ai/LanguageModel.ts +54 -24
- package/src/unstable/ai/McpSchema.ts +57 -11
- package/src/unstable/ai/McpServer.ts +44 -6
- package/src/unstable/ai/Tool.ts +15 -0
- package/src/unstable/cluster/ClusterWorkflowEngine.ts +2 -2
- package/src/unstable/http/HttpClient.ts +45 -10
- package/src/unstable/http/HttpEffect.ts +20 -39
- package/src/unstable/http/HttpMiddleware.ts +4 -14
- package/src/unstable/http/HttpServerError.ts +29 -18
- package/src/unstable/http/internal/preResponseHandler.ts +15 -0
- package/src/unstable/httpapi/HttpApiBuilder.ts +1 -1
- package/src/unstable/reactivity/Atom.ts +1 -1
- package/src/unstable/rpc/RpcSchema.ts +17 -0
- package/src/unstable/rpc/RpcSerialization.ts +44 -9
- package/src/unstable/rpc/RpcServer.ts +10 -19
package/src/internal/effect.ts
CHANGED
|
@@ -492,33 +492,33 @@ const fiberIdStore = { id: 0 }
|
|
|
492
492
|
export const getCurrentFiber = (): Fiber.Fiber<any, any> | undefined => (globalThis as any)[currentFiberTypeId]
|
|
493
493
|
|
|
494
494
|
const keepAlive = (() => {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
495
|
+
let isAvailable: boolean | undefined
|
|
496
|
+
const start = () => {
|
|
497
|
+
if (isAvailable === true) return setInterval(constVoid, 2_147_483_647)
|
|
498
|
+
else if (isAvailable === false) return undefined
|
|
499
|
+
|
|
498
500
|
try {
|
|
499
501
|
const running = setInterval(constVoid, 2_147_483_647)
|
|
500
|
-
|
|
501
|
-
return
|
|
502
|
-
setInterval,
|
|
503
|
-
clearInterval
|
|
504
|
-
}
|
|
502
|
+
isAvailable = true
|
|
503
|
+
return running
|
|
505
504
|
} catch {
|
|
505
|
+
isAvailable = false
|
|
506
506
|
return undefined
|
|
507
507
|
}
|
|
508
|
-
}
|
|
508
|
+
}
|
|
509
509
|
let count = 0
|
|
510
510
|
let running: ReturnType<typeof globalThis.setInterval> | undefined = undefined
|
|
511
511
|
return ({
|
|
512
512
|
increment() {
|
|
513
513
|
count++
|
|
514
|
-
if (
|
|
515
|
-
running = start
|
|
514
|
+
if (running === undefined) {
|
|
515
|
+
running = start()
|
|
516
516
|
}
|
|
517
517
|
},
|
|
518
518
|
decrement() {
|
|
519
519
|
count--
|
|
520
|
-
if (count === 0 &&
|
|
521
|
-
|
|
520
|
+
if (count === 0 && running !== undefined) {
|
|
521
|
+
clearInterval(running)
|
|
522
522
|
running = undefined
|
|
523
523
|
}
|
|
524
524
|
}
|
|
@@ -832,13 +832,29 @@ export const fiberInterrupt = <A, E>(
|
|
|
832
832
|
|
|
833
833
|
/** @internal */
|
|
834
834
|
export const fiberInterruptAs: {
|
|
835
|
-
(
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
835
|
+
(
|
|
836
|
+
fiberId: number | undefined,
|
|
837
|
+
annotations?: ServiceMap.ServiceMap<never> | undefined
|
|
838
|
+
): <A, E>(self: Fiber.Fiber<A, E>) => Effect.Effect<void>
|
|
839
|
+
<A, E>(
|
|
840
|
+
self: Fiber.Fiber<A, E>,
|
|
841
|
+
fiberId: number | undefined,
|
|
842
|
+
annotations?: ServiceMap.ServiceMap<never> | undefined
|
|
843
|
+
): Effect.Effect<void>
|
|
844
|
+
} = dual(
|
|
845
|
+
(args) => hasProperty(args[0], FiberTypeId),
|
|
846
|
+
<A, E>(
|
|
847
|
+
self: Fiber.Fiber<A, E>,
|
|
848
|
+
fiberId: number | undefined,
|
|
849
|
+
annotations?: ServiceMap.ServiceMap<never> | undefined
|
|
850
|
+
): Effect.Effect<void> =>
|
|
851
|
+
withFiber((parent) => {
|
|
852
|
+
let ann = fiberStackAnnotations(parent)
|
|
853
|
+
ann = ann && annotations ? ServiceMap.merge(ann, annotations) : ann ?? annotations
|
|
854
|
+
self.interruptUnsafe(fiberId, ann)
|
|
855
|
+
return asVoid(fiberAwait(self))
|
|
856
|
+
})
|
|
857
|
+
)
|
|
842
858
|
|
|
843
859
|
/** @internal */
|
|
844
860
|
export const fiberInterruptAll = <A extends Iterable<Fiber.Fiber<any, any>>>(
|
|
@@ -2003,23 +2019,8 @@ export const updateServices: {
|
|
|
2003
2019
|
const nextServices = f(prev)
|
|
2004
2020
|
if (prev === nextServices) return self as any
|
|
2005
2021
|
fiber.setServices(nextServices)
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
if (!prev.mapUnsafe.has(key) || value !== prev.mapUnsafe.get(key)) {
|
|
2009
|
-
newServices.set(key, value)
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
return onExitPrimitive(self as any, () => {
|
|
2013
|
-
const map = new Map(fiber.services.mapUnsafe)
|
|
2014
|
-
for (const [key, value] of newServices) {
|
|
2015
|
-
if (value !== map.get(key)) continue
|
|
2016
|
-
if (prev.mapUnsafe.has(key)) {
|
|
2017
|
-
map.set(key, prev.mapUnsafe.get(key))
|
|
2018
|
-
} else {
|
|
2019
|
-
map.delete(key)
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
fiber.setServices(ServiceMap.makeUnsafe(map))
|
|
2022
|
+
return onExitPrimitive(self, () => {
|
|
2023
|
+
fiber.setServices(prev)
|
|
2023
2024
|
return undefined
|
|
2024
2025
|
})
|
|
2025
2026
|
})
|
|
@@ -2043,12 +2044,11 @@ export const updateService: {
|
|
|
2043
2044
|
service: ServiceMap.Service<I, A>,
|
|
2044
2045
|
f: (value: A) => A
|
|
2045
2046
|
): Effect.Effect<XA, E, R | I> =>
|
|
2046
|
-
|
|
2047
|
-
const prev = ServiceMap.getUnsafe(
|
|
2047
|
+
updateServices(self, (s) => {
|
|
2048
|
+
const prev = ServiceMap.getUnsafe(s, service)
|
|
2048
2049
|
const next = f(prev)
|
|
2049
|
-
if (prev === next) return
|
|
2050
|
-
|
|
2051
|
-
return onExit(self, () => sync(() => fiber.setServices(ServiceMap.add(fiber.services, service, prev))))
|
|
2050
|
+
if (prev === next) return s
|
|
2051
|
+
return ServiceMap.add(s, service, next)
|
|
2052
2052
|
})
|
|
2053
2053
|
)
|
|
2054
2054
|
|
|
@@ -2115,11 +2115,10 @@ const provideServiceImpl = <A, E, R, I, S>(
|
|
|
2115
2115
|
service: ServiceMap.Service<I, S>,
|
|
2116
2116
|
implementation: S
|
|
2117
2117
|
): Effect.Effect<A, E, Exclude<R, I>> =>
|
|
2118
|
-
|
|
2119
|
-
const prev =
|
|
2120
|
-
if (prev
|
|
2121
|
-
|
|
2122
|
-
return onExit(self, () => sync(() => fiber.setServices(ServiceMap.addOrOmit(fiber.services, service, prev))))
|
|
2118
|
+
updateServices(self, (s) => {
|
|
2119
|
+
const prev = s.mapUnsafe.get(service.key)
|
|
2120
|
+
if (prev === implementation) return s
|
|
2121
|
+
return ServiceMap.add(s, service, implementation)
|
|
2123
2122
|
}) as any
|
|
2124
2123
|
|
|
2125
2124
|
/** @internal */
|
|
@@ -3666,11 +3665,11 @@ export const provideScope: {
|
|
|
3666
3665
|
/** @internal */
|
|
3667
3666
|
export const scoped = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, Exclude<R, Scope.Scope>> =>
|
|
3668
3667
|
withFiber((fiber) => {
|
|
3669
|
-
const prev =
|
|
3668
|
+
const prev = fiber.services
|
|
3670
3669
|
const scope = scopeMakeUnsafe()
|
|
3671
3670
|
fiber.setServices(ServiceMap.add(fiber.services, scopeTag, scope))
|
|
3672
3671
|
return onExitPrimitive(self, (exit) => {
|
|
3673
|
-
fiber.setServices(
|
|
3672
|
+
fiber.setServices(prev)
|
|
3674
3673
|
return scopeCloseUnsafe(scope, exit)
|
|
3675
3674
|
})
|
|
3676
3675
|
}) as any
|
|
@@ -5555,6 +5554,40 @@ export const LogToStderr = ServiceMap.Reference<boolean>("effect/Logger/LogToStd
|
|
|
5555
5554
|
defaultValue: constFalse
|
|
5556
5555
|
})
|
|
5557
5556
|
|
|
5557
|
+
/** @internal */
|
|
5558
|
+
export const annotateLogsScoped: {
|
|
5559
|
+
(key: string, value: unknown): Effect.Effect<void, never, Scope.Scope>
|
|
5560
|
+
(values: Record<string, unknown>): Effect.Effect<void, never, Scope.Scope>
|
|
5561
|
+
} = function() {
|
|
5562
|
+
const entries = typeof arguments[0] === "string" ?
|
|
5563
|
+
[[arguments[0], arguments[1]]] :
|
|
5564
|
+
Object.entries(arguments[0])
|
|
5565
|
+
return uninterruptible(withFiber((fiber) => {
|
|
5566
|
+
const prev = fiber.getRef(CurrentLogAnnotations)
|
|
5567
|
+
const next = { ...prev }
|
|
5568
|
+
for (let i = 0; i < entries.length; i++) {
|
|
5569
|
+
const [key, value] = entries[i]
|
|
5570
|
+
next[key] = value
|
|
5571
|
+
}
|
|
5572
|
+
fiber.setServices(ServiceMap.add(fiber.services, CurrentLogAnnotations, next))
|
|
5573
|
+
return scopeAddFinalizerExit(ServiceMap.getUnsafe(fiber.services, scopeTag), (_) => {
|
|
5574
|
+
const current = fiber.getRef(CurrentLogAnnotations)
|
|
5575
|
+
const next = { ...current }
|
|
5576
|
+
for (let i = 0; i < entries.length; i++) {
|
|
5577
|
+
const [key, value] = entries[i]
|
|
5578
|
+
if (current[key] !== value) continue
|
|
5579
|
+
if (key in prev) {
|
|
5580
|
+
next[key] = prev[key]
|
|
5581
|
+
} else {
|
|
5582
|
+
delete next[key]
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
fiber.setServices(ServiceMap.add(fiber.services, CurrentLogAnnotations, next))
|
|
5586
|
+
return void_
|
|
5587
|
+
})
|
|
5588
|
+
}))
|
|
5589
|
+
}
|
|
5590
|
+
|
|
5558
5591
|
/** @internal */
|
|
5559
5592
|
export const LoggerTypeId = "~effect/Logger"
|
|
5560
5593
|
|
|
@@ -949,9 +949,8 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
949
949
|
return content as Array<Response.Part<Tools>>
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
-
// Pre-resolve tool approvals before calling the LLM
|
|
952
|
+
// Pre-resolve pending tool approvals before calling the LLM
|
|
953
953
|
if (hasPendingApprovals) {
|
|
954
|
-
// Validate all approved tools exist in the toolkit
|
|
955
954
|
for (const approval of approved) {
|
|
956
955
|
if (approval.toolCall && !toolkit.tools[approval.toolCall.name]) {
|
|
957
956
|
return yield* AiError.make({
|
|
@@ -965,7 +964,6 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
965
964
|
}
|
|
966
965
|
}
|
|
967
966
|
|
|
968
|
-
// Execute approved tools and create denial results
|
|
969
967
|
const approvedResults = yield* executeApprovedToolCalls(
|
|
970
968
|
approved,
|
|
971
969
|
toolkit,
|
|
@@ -974,23 +972,27 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
974
972
|
const deniedResults = createDenialResults(denied)
|
|
975
973
|
const preResolvedResults = [...approvedResults, ...deniedResults]
|
|
976
974
|
|
|
977
|
-
// Add pre-resolved results to the prompt
|
|
978
975
|
if (preResolvedResults.length > 0) {
|
|
979
|
-
const toolMessage = Prompt.makeMessage("tool", {
|
|
980
|
-
content: preResolvedResults
|
|
981
|
-
})
|
|
982
976
|
providerOptions.prompt = Prompt.fromMessages([
|
|
983
977
|
...providerOptions.prompt.content,
|
|
984
|
-
|
|
978
|
+
Prompt.makeMessage("tool", { content: preResolvedResults })
|
|
985
979
|
])
|
|
986
980
|
}
|
|
981
|
+
}
|
|
987
982
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
983
|
+
// Strip all resolved approval artifacts (both current and from previous
|
|
984
|
+
// rounds) in a single pass before sending to the provider.
|
|
985
|
+
{
|
|
986
|
+
const { approved: allResolved, denied: allDenied } = collectToolApprovals(
|
|
987
|
+
providerOptions.prompt.content
|
|
993
988
|
)
|
|
989
|
+
if (allResolved.length > 0 || allDenied.length > 0) {
|
|
990
|
+
providerOptions.prompt = stripResolvedApprovals(
|
|
991
|
+
providerOptions.prompt,
|
|
992
|
+
allResolved,
|
|
993
|
+
allDenied
|
|
994
|
+
)
|
|
995
|
+
}
|
|
994
996
|
}
|
|
995
997
|
|
|
996
998
|
const tools = typeof toolChoice === "object" && "oneOf" in toolChoice
|
|
@@ -1137,9 +1139,10 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
1137
1139
|
>
|
|
1138
1140
|
}
|
|
1139
1141
|
|
|
1140
|
-
// Pre-resolve tool approvals before calling the LLM
|
|
1142
|
+
// Pre-resolve pending tool approvals before calling the LLM
|
|
1143
|
+
let preResolvedStreamParts: Array<Response.StreamPart<Tools>> = []
|
|
1144
|
+
|
|
1141
1145
|
if (hasPendingApprovals) {
|
|
1142
|
-
// Validate all approved tools exist in the toolkit
|
|
1143
1146
|
for (const approval of pendingApproved) {
|
|
1144
1147
|
if (approval.toolCall && !toolkit.tools[approval.toolCall.name]) {
|
|
1145
1148
|
return yield* AiError.make({
|
|
@@ -1153,7 +1156,6 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
1153
1156
|
}
|
|
1154
1157
|
}
|
|
1155
1158
|
|
|
1156
|
-
// Execute approved tools and create denial results
|
|
1157
1159
|
const approvedResults = yield* executeApprovedToolCalls(
|
|
1158
1160
|
pendingApproved,
|
|
1159
1161
|
toolkit,
|
|
@@ -1162,22 +1164,43 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
1162
1164
|
const deniedResults = createDenialResults(pendingDenied)
|
|
1163
1165
|
const preResolvedResults = [...approvedResults, ...deniedResults]
|
|
1164
1166
|
|
|
1165
|
-
// Add pre-resolved results to the prompt
|
|
1166
1167
|
if (preResolvedResults.length > 0) {
|
|
1167
|
-
const toolMessage = Prompt.makeMessage("tool", {
|
|
1168
|
-
content: preResolvedResults
|
|
1169
|
-
})
|
|
1170
1168
|
providerOptions.prompt = Prompt.fromMessages([
|
|
1171
1169
|
...providerOptions.prompt.content,
|
|
1172
|
-
|
|
1170
|
+
Prompt.makeMessage("tool", { content: preResolvedResults })
|
|
1173
1171
|
])
|
|
1174
1172
|
}
|
|
1175
1173
|
|
|
1176
|
-
//
|
|
1174
|
+
// Emit pre-resolved tool-results as stream parts so Chat.streamText
|
|
1175
|
+
// persists them to history. This lets collectToolApprovals find them
|
|
1176
|
+
// on subsequent rounds and skip the now-resolved approvals.
|
|
1177
|
+
// Note: r.result is already encoded (from executeApprovedToolCalls /
|
|
1178
|
+
// createDenialResults), so it goes into both result and encodedResult.
|
|
1179
|
+
for (const r of preResolvedResults) {
|
|
1180
|
+
preResolvedStreamParts.push(
|
|
1181
|
+
Response.makePart("tool-result", {
|
|
1182
|
+
id: r.id,
|
|
1183
|
+
name: r.name,
|
|
1184
|
+
providerExecuted: false,
|
|
1185
|
+
preliminary: false,
|
|
1186
|
+
result: r.result,
|
|
1187
|
+
encodedResult: r.result,
|
|
1188
|
+
isFailure: r.isFailure
|
|
1189
|
+
}) as Response.StreamPart<Tools>
|
|
1190
|
+
)
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// Strip all resolved approval artifacts (both current and from previous
|
|
1195
|
+
// rounds) in a single pass before sending to the provider.
|
|
1196
|
+
const { approved: allResolved, denied: allDenied } = collectToolApprovals(
|
|
1197
|
+
providerOptions.prompt.content
|
|
1198
|
+
)
|
|
1199
|
+
if (allResolved.length > 0 || allDenied.length > 0) {
|
|
1177
1200
|
providerOptions.prompt = stripResolvedApprovals(
|
|
1178
1201
|
providerOptions.prompt,
|
|
1179
|
-
|
|
1180
|
-
|
|
1202
|
+
allResolved,
|
|
1203
|
+
allDenied
|
|
1181
1204
|
)
|
|
1182
1205
|
}
|
|
1183
1206
|
|
|
@@ -1215,6 +1238,13 @@ export const make: (params: ConstructorParams) => Effect.Effect<Service> = Effec
|
|
|
1215
1238
|
| Schema.SchemaError
|
|
1216
1239
|
>()
|
|
1217
1240
|
|
|
1241
|
+
// Emit pre-resolved tool results so Chat.streamText persists them to
|
|
1242
|
+
// history. This ensures collectToolApprovals({ excludeResolved }) can
|
|
1243
|
+
// find the corresponding tool-results on future rounds.
|
|
1244
|
+
if (preResolvedStreamParts.length > 0) {
|
|
1245
|
+
yield* Queue.offerAll(queue, preResolvedStreamParts)
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1218
1248
|
// FiberSet to track concurrent tool call handlers
|
|
1219
1249
|
const toolCallFibers = yield* FiberSet.make<void, AiError.AiError>()
|
|
1220
1250
|
|
|
@@ -240,6 +240,11 @@ export class ClientCapabilities extends Schema.Class<ClientCapabilities>(
|
|
|
240
240
|
* Experimental, non-standard capabilities that the client supports.
|
|
241
241
|
*/
|
|
242
242
|
experimental: optional(Schema.Record(Schema.String, Schema.Struct({}))),
|
|
243
|
+
/**
|
|
244
|
+
* Optional extensions capabilities advertised by the client.
|
|
245
|
+
* Keys are extension identifiers following <vendor-prefix>/<extension-name> (e.g. "io.modelcontextprotocol/ui").
|
|
246
|
+
*/
|
|
247
|
+
extensions: optional(Schema.Record(Schema.TemplateLiteral([Schema.String, "/", Schema.String]), Schema.Unknown)),
|
|
243
248
|
/**
|
|
244
249
|
* Present if the client supports listing roots.
|
|
245
250
|
*/
|
|
@@ -272,6 +277,11 @@ export class ServerCapabilities extends Schema.Opaque<ServerCapabilities>()(Sche
|
|
|
272
277
|
* Experimental, non-standard capabilities that the server supports.
|
|
273
278
|
*/
|
|
274
279
|
experimental: optional(Schema.Record(Schema.String, Schema.Struct({}))),
|
|
280
|
+
/**
|
|
281
|
+
* Optional extensions capabilities advertised by the server.
|
|
282
|
+
* Keys are extension identifiers following <vendor-prefix>/<extension-name> (e.g. "io.modelcontextprotocol/ui").
|
|
283
|
+
*/
|
|
284
|
+
extensions: optional(Schema.Record(Schema.TemplateLiteral([Schema.String, "/", Schema.String]), Schema.Unknown)),
|
|
275
285
|
/**
|
|
276
286
|
* Present if the server supports sending log messages to the client.
|
|
277
287
|
*/
|
|
@@ -321,8 +331,8 @@ export class ServerCapabilities extends Schema.Opaque<ServerCapabilities>()(Sche
|
|
|
321
331
|
* @since 4.0.0
|
|
322
332
|
* @category errors
|
|
323
333
|
*/
|
|
324
|
-
export class
|
|
325
|
-
"@effect/ai/McpSchema/
|
|
334
|
+
export class McpErrorBase extends Schema.Class<McpErrorBase>(
|
|
335
|
+
"@effect/ai/McpSchema/McpErrorBase"
|
|
326
336
|
)({
|
|
327
337
|
/**
|
|
328
338
|
* The error type that occurred.
|
|
@@ -371,7 +381,7 @@ export const PARSE_ERROR_CODE = -32700 as const
|
|
|
371
381
|
* @category errors
|
|
372
382
|
*/
|
|
373
383
|
export class ParseError extends Schema.ErrorClass<ParseError>("effect/ai/McpSchema/ParseError")({
|
|
374
|
-
...
|
|
384
|
+
...McpErrorBase.fields,
|
|
375
385
|
_tag: Schema.tag("ParseError"),
|
|
376
386
|
code: Schema.tag(PARSE_ERROR_CODE)
|
|
377
387
|
}) {}
|
|
@@ -381,7 +391,7 @@ export class ParseError extends Schema.ErrorClass<ParseError>("effect/ai/McpSche
|
|
|
381
391
|
* @category errors
|
|
382
392
|
*/
|
|
383
393
|
export class InvalidRequest extends Schema.ErrorClass<InvalidRequest>("effect/ai/McpSchema/InvalidRequest")({
|
|
384
|
-
...
|
|
394
|
+
...McpErrorBase.fields,
|
|
385
395
|
_tag: Schema.tag("InvalidRequest"),
|
|
386
396
|
code: Schema.tag(INVALID_REQUEST_ERROR_CODE)
|
|
387
397
|
}) {}
|
|
@@ -391,7 +401,7 @@ export class InvalidRequest extends Schema.ErrorClass<InvalidRequest>("effect/ai
|
|
|
391
401
|
* @category errors
|
|
392
402
|
*/
|
|
393
403
|
export class MethodNotFound extends Schema.ErrorClass<MethodNotFound>("effect/ai/McpSchema/MethodNotFound")({
|
|
394
|
-
...
|
|
404
|
+
...McpErrorBase.fields,
|
|
395
405
|
_tag: Schema.tag("MethodNotFound"),
|
|
396
406
|
code: Schema.tag(METHOD_NOT_FOUND_ERROR_CODE)
|
|
397
407
|
}) {}
|
|
@@ -401,7 +411,7 @@ export class MethodNotFound extends Schema.ErrorClass<MethodNotFound>("effect/ai
|
|
|
401
411
|
* @category errors
|
|
402
412
|
*/
|
|
403
413
|
export class InvalidParams extends Schema.ErrorClass<InvalidParams>("effect/ai/McpSchema/InvalidParams")({
|
|
404
|
-
...
|
|
414
|
+
...McpErrorBase.fields,
|
|
405
415
|
_tag: Schema.tag("InvalidParams"),
|
|
406
416
|
code: Schema.tag(INVALID_PARAMS_ERROR_CODE)
|
|
407
417
|
}) {}
|
|
@@ -411,13 +421,26 @@ export class InvalidParams extends Schema.ErrorClass<InvalidParams>("effect/ai/M
|
|
|
411
421
|
* @category errors
|
|
412
422
|
*/
|
|
413
423
|
export class InternalError extends Schema.ErrorClass<InternalError>("effect/ai/McpSchema/InternalError")({
|
|
414
|
-
...
|
|
424
|
+
...McpErrorBase.fields,
|
|
415
425
|
_tag: Schema.tag("InternalError"),
|
|
416
426
|
code: Schema.tag(INTERNAL_ERROR_CODE)
|
|
417
427
|
}) {
|
|
418
428
|
static readonly notImplemented = new InternalError({ message: "Not implemented" })
|
|
419
429
|
}
|
|
420
430
|
|
|
431
|
+
/**
|
|
432
|
+
* @since 4.0.0
|
|
433
|
+
* @category errors
|
|
434
|
+
*/
|
|
435
|
+
export const McpError = Schema.Union([
|
|
436
|
+
ParseError,
|
|
437
|
+
InvalidRequest,
|
|
438
|
+
MethodNotFound,
|
|
439
|
+
InvalidParams,
|
|
440
|
+
InternalError,
|
|
441
|
+
McpErrorBase
|
|
442
|
+
])
|
|
443
|
+
|
|
421
444
|
// =============================================================================
|
|
422
445
|
// Ping
|
|
423
446
|
// =============================================================================
|
|
@@ -615,7 +638,14 @@ export class Resource extends Schema.Class<Resource>(
|
|
|
615
638
|
* This can be used by Hosts to display file sizes and estimate context
|
|
616
639
|
* window usage.
|
|
617
640
|
*/
|
|
618
|
-
size: optional(Schema.Number)
|
|
641
|
+
size: optional(Schema.Number),
|
|
642
|
+
/**
|
|
643
|
+
* Optional additional metadata for the client.
|
|
644
|
+
*
|
|
645
|
+
* This parameter name is reserved by MCP to allow clients and servers to
|
|
646
|
+
* attach additional metadata to resources.
|
|
647
|
+
*/
|
|
648
|
+
_meta: optional(Schema.Record(Schema.String, Schema.Unknown))
|
|
619
649
|
}) {}
|
|
620
650
|
|
|
621
651
|
/**
|
|
@@ -656,7 +686,12 @@ export class ResourceTemplate extends Schema.Class<ResourceTemplate>(
|
|
|
656
686
|
/**
|
|
657
687
|
* Optional annotations for the client.
|
|
658
688
|
*/
|
|
659
|
-
annotations: optional(Annotations)
|
|
689
|
+
annotations: optional(Annotations),
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Optional additional metadata for the client.
|
|
693
|
+
*/
|
|
694
|
+
_meta: optional(Schema.Record(Schema.String, Schema.Unknown))
|
|
660
695
|
}) {}
|
|
661
696
|
|
|
662
697
|
/**
|
|
@@ -673,7 +708,11 @@ export class ResourceContents extends Schema.Opaque<ResourceContents>()(Schema.S
|
|
|
673
708
|
/**
|
|
674
709
|
* The MIME type of this resource, if known.
|
|
675
710
|
*/
|
|
676
|
-
mimeType: optional(Schema.String)
|
|
711
|
+
mimeType: optional(Schema.String),
|
|
712
|
+
/**
|
|
713
|
+
* Optional additional metadata for the client.
|
|
714
|
+
*/
|
|
715
|
+
_meta: optional(Schema.Record(Schema.String, Schema.Unknown))
|
|
677
716
|
})) {}
|
|
678
717
|
|
|
679
718
|
/**
|
|
@@ -1183,7 +1222,14 @@ export class Tool extends Schema.Class<Tool>(
|
|
|
1183
1222
|
/**
|
|
1184
1223
|
* Optional additional tool information.
|
|
1185
1224
|
*/
|
|
1186
|
-
annotations: optional(ToolAnnotations)
|
|
1225
|
+
annotations: optional(ToolAnnotations),
|
|
1226
|
+
/**
|
|
1227
|
+
* Optional additional metadata for the client.
|
|
1228
|
+
*
|
|
1229
|
+
* This parameter name is reserved by MCP to allow clients and servers to
|
|
1230
|
+
* attach additional metadata to resources.
|
|
1231
|
+
*/
|
|
1232
|
+
_meta: optional(Schema.Record(Schema.String, Schema.Unknown))
|
|
1187
1233
|
}) {}
|
|
1188
1234
|
|
|
1189
1235
|
/**
|
|
@@ -9,6 +9,7 @@ import * as Layer from "../../Layer.ts"
|
|
|
9
9
|
import * as Option from "../../Option.ts"
|
|
10
10
|
import * as Queue from "../../Queue.ts"
|
|
11
11
|
import * as RcMap from "../../RcMap.ts"
|
|
12
|
+
import { CurrentLogLevel } from "../../References.ts"
|
|
12
13
|
import * as Schema from "../../Schema.ts"
|
|
13
14
|
import * as AST from "../../SchemaAST.ts"
|
|
14
15
|
import * as ServiceMap from "../../ServiceMap.ts"
|
|
@@ -548,6 +549,7 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
|
|
|
548
549
|
>)
|
|
549
550
|
const services = yield* Effect.services<never>()
|
|
550
551
|
for (const tool of Object.values(built.tools)) {
|
|
552
|
+
const toolMeta = ServiceMap.getOrUndefined(tool.annotations, Tool.Meta)
|
|
551
553
|
const mcpTool = new McpTool({
|
|
552
554
|
name: tool.name,
|
|
553
555
|
description: Tool.getDescription(tool),
|
|
@@ -561,7 +563,8 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
|
|
|
561
563
|
destructiveHint: ServiceMap.get(tool.annotations, Tool.Destructive),
|
|
562
564
|
idempotentHint: ServiceMap.get(tool.annotations, Tool.Idempotent),
|
|
563
565
|
openWorldHint: ServiceMap.get(tool.annotations, Tool.OpenWorld)
|
|
564
|
-
}
|
|
566
|
+
},
|
|
567
|
+
_meta: toolMeta
|
|
565
568
|
})
|
|
566
569
|
yield* registry.addTool({
|
|
567
570
|
tool: mcpTool,
|
|
@@ -1075,6 +1078,7 @@ const layerHandlers = (serverInfo: {
|
|
|
1075
1078
|
ClientRpcs.toLayer(
|
|
1076
1079
|
Effect.gen(function*() {
|
|
1077
1080
|
const server = yield* McpServer
|
|
1081
|
+
let currentLogLevel = yield* CurrentLogLevel
|
|
1078
1082
|
|
|
1079
1083
|
return ClientRpcs.of({
|
|
1080
1084
|
// Requests
|
|
@@ -1105,17 +1109,51 @@ const layerHandlers = (serverInfo: {
|
|
|
1105
1109
|
: LATEST_PROTOCOL_VERSION
|
|
1106
1110
|
})
|
|
1107
1111
|
},
|
|
1108
|
-
"completion/complete":
|
|
1109
|
-
|
|
1110
|
-
|
|
1112
|
+
"completion/complete": (r) =>
|
|
1113
|
+
server.completion(r).pipe(
|
|
1114
|
+
Effect.provideService(CurrentLogLevel, currentLogLevel)
|
|
1115
|
+
),
|
|
1116
|
+
"logging/setLevel": ({ level }) =>
|
|
1117
|
+
Effect.sync(() => {
|
|
1118
|
+
switch (level) {
|
|
1119
|
+
case "notice":
|
|
1120
|
+
case "info":
|
|
1121
|
+
currentLogLevel = "Info"
|
|
1122
|
+
break
|
|
1123
|
+
case "error":
|
|
1124
|
+
currentLogLevel = "Error"
|
|
1125
|
+
break
|
|
1126
|
+
case "debug":
|
|
1127
|
+
currentLogLevel = "Debug"
|
|
1128
|
+
break
|
|
1129
|
+
case "warning":
|
|
1130
|
+
currentLogLevel = "Warn"
|
|
1131
|
+
break
|
|
1132
|
+
case "critical":
|
|
1133
|
+
case "alert":
|
|
1134
|
+
case "emergency":
|
|
1135
|
+
currentLogLevel = "Fatal"
|
|
1136
|
+
break
|
|
1137
|
+
}
|
|
1138
|
+
}),
|
|
1139
|
+
"prompts/get": (r) =>
|
|
1140
|
+
server.getPromptResult(r).pipe(
|
|
1141
|
+
Effect.provideService(CurrentLogLevel, currentLogLevel)
|
|
1142
|
+
),
|
|
1111
1143
|
"prompts/list": () => Effect.sync(() => new ListPromptsResult({ prompts: server.prompts })),
|
|
1112
1144
|
"resources/list": () => Effect.sync(() => new ListResourcesResult({ resources: server.resources })),
|
|
1113
|
-
"resources/read": ({ uri }) =>
|
|
1145
|
+
"resources/read": ({ uri }) =>
|
|
1146
|
+
server.findResource(uri).pipe(
|
|
1147
|
+
Effect.provideService(CurrentLogLevel, currentLogLevel)
|
|
1148
|
+
),
|
|
1114
1149
|
"resources/subscribe": () => InternalError.notImplemented.asEffect(),
|
|
1115
1150
|
"resources/unsubscribe": () => InternalError.notImplemented.asEffect(),
|
|
1116
1151
|
"resources/templates/list": () =>
|
|
1117
1152
|
Effect.sync(() => new ListResourceTemplatesResult({ resourceTemplates: server.resourceTemplates })),
|
|
1118
|
-
"tools/call":
|
|
1153
|
+
"tools/call": (r) =>
|
|
1154
|
+
server.callTool(r).pipe(
|
|
1155
|
+
Effect.provideService(CurrentLogLevel, currentLogLevel)
|
|
1156
|
+
),
|
|
1119
1157
|
"tools/list": () => Effect.sync(() => new ListToolsResult({ tools: server.tools })),
|
|
1120
1158
|
|
|
1121
1159
|
// Notifications
|
package/src/unstable/ai/Tool.ts
CHANGED
|
@@ -1661,6 +1661,21 @@ export const getJsonSchemaFromSchema = <S extends Schema.Top>(schema: S, options
|
|
|
1661
1661
|
*/
|
|
1662
1662
|
export class Title extends ServiceMap.Service<Title, string>()("effect/ai/Tool/Title") {}
|
|
1663
1663
|
|
|
1664
|
+
/**
|
|
1665
|
+
* Annotation for providing tool metadata for MCP.
|
|
1666
|
+
*
|
|
1667
|
+
* @example
|
|
1668
|
+
* ```ts
|
|
1669
|
+
* import { Tool } from "effect/unstable/ai"
|
|
1670
|
+
*
|
|
1671
|
+
* const myCalculatorUi = Tool.make("calculator_ui", {})
|
|
1672
|
+
* .annotate(Tool.Meta, { ui: { resourceUri: "ui://example/calculator-ui" } })
|
|
1673
|
+
* ```
|
|
1674
|
+
* @since 1.0.0
|
|
1675
|
+
* @category annotations
|
|
1676
|
+
*/
|
|
1677
|
+
export class Meta extends ServiceMap.Service<Meta, Record<string, unknown>>()("effect/ai/Tool/Meta") {}
|
|
1678
|
+
|
|
1664
1679
|
/**
|
|
1665
1680
|
* Annotation indicating whether a tool only reads data without making changes.
|
|
1666
1681
|
*
|
|
@@ -16,7 +16,7 @@ import * as Schema from "../../Schema.ts"
|
|
|
16
16
|
import type * as Scope from "../../Scope.ts"
|
|
17
17
|
import * as ServiceMap from "../../ServiceMap.ts"
|
|
18
18
|
import * as Rpc from "../rpc/Rpc.ts"
|
|
19
|
-
import
|
|
19
|
+
import { ClientAbort } from "../rpc/RpcSchema.ts"
|
|
20
20
|
import * as Activity from "../workflow/Activity.ts"
|
|
21
21
|
import * as DurableClock from "../workflow/DurableClock.ts"
|
|
22
22
|
import * as DurableDeferred from "../workflow/DurableDeferred.ts"
|
|
@@ -315,7 +315,7 @@ export const make = Effect.gen(function*() {
|
|
|
315
315
|
// we only want to store interrupts as suspends when the
|
|
316
316
|
// client requested it
|
|
317
317
|
const suspend = cause.reasons.some((f) =>
|
|
318
|
-
f._tag === "Interrupt" && f.
|
|
318
|
+
f._tag === "Interrupt" && f.annotations.has(ClientAbort.key)
|
|
319
319
|
)
|
|
320
320
|
if (suspend) {
|
|
321
321
|
interruptedActivities.add(activityId)
|