@animalabs/agent-framework 0.23.2 → 0.24.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 +212 -42
- package/dist/src/agent.d.ts +60 -9
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +92 -12
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +14 -12
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/code-execution/engine.d.ts +177 -0
- package/dist/src/code-execution/engine.d.ts.map +1 -0
- package/dist/src/code-execution/engine.js +494 -0
- package/dist/src/code-execution/engine.js.map +1 -0
- package/dist/src/code-execution/index.d.ts +5 -10
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js +5 -9
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/isolate/calls.d.ts +114 -0
- package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/calls.js +145 -0
- package/dist/src/code-execution/isolate/calls.js.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.js +5 -0
- package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
- package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
- package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-main.js +132 -0
- package/dist/src/code-execution/isolate/child-main.js.map +1 -0
- package/dist/src/code-execution/isolate/child.d.ts +44 -0
- package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child.js +315 -0
- package/dist/src/code-execution/isolate/child.js.map +1 -0
- package/dist/src/code-execution/isolate/frames.d.ts +80 -0
- package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/frames.js +210 -0
- package/dist/src/code-execution/isolate/frames.js.map +1 -0
- package/dist/src/code-execution/isolate/output.d.ts +68 -0
- package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/output.js +143 -0
- package/dist/src/code-execution/isolate/output.js.map +1 -0
- package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
- package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/prelude.js +401 -0
- package/dist/src/code-execution/isolate/prelude.js.map +1 -0
- package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
- package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/protocol.js +150 -0
- package/dist/src/code-execution/isolate/protocol.js.map +1 -0
- package/dist/src/code-execution/isolate/render.d.ts +57 -0
- package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/render.js +214 -0
- package/dist/src/code-execution/isolate/render.js.map +1 -0
- package/dist/src/code-execution/isolate/runner.d.ts +250 -0
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/runner.js +854 -0
- package/dist/src/code-execution/isolate/runner.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/scripts.js +357 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -0
- package/dist/src/code-execution/quickjs.wasm +0 -0
- package/dist/src/code-execution/tool-definition.d.ts +93 -43
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +176 -142
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/deadline-timer.d.ts +3 -0
- package/dist/src/deadline-timer.d.ts.map +1 -1
- package/dist/src/deadline-timer.js +1 -1
- package/dist/src/deadline-timer.js.map +1 -1
- package/dist/src/framework.d.ts +1027 -440
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4093 -2238
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +28 -1
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +88 -10
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -3
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +16 -3
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +6 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +471 -75
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1673 -337
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +12 -7
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +12 -7
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +9 -5
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +50 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +130 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +2 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -2
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +6 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +8 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +15 -6
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +168 -53
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -5
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +4 -5
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +97 -10
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +173 -16
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -14
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +227 -50
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +6 -1
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +4 -1
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +4 -4
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +50 -21
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +158 -74
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +33 -0
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +55 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +163 -34
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +22 -6
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +4 -2
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +100 -13
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +8 -13
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +27 -4
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +15 -3
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +27 -5
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +4 -1
- package/dist/src/modules/unknown-tool.d.ts.map +1 -1
- package/dist/src/modules/unknown-tool.js +4 -1
- package/dist/src/modules/unknown-tool.js.map +1 -1
- package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +3 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
- package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-plan.js +794 -0
- package/dist/src/modules/workspace/edit-plan.js.map +1 -0
- package/dist/src/modules/workspace/edit-text.d.ts +117 -0
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-text.js +584 -0
- package/dist/src/modules/workspace/edit-text.js.map +1 -0
- package/dist/src/modules/workspace/effects.d.ts +5 -4
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +78 -25
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +484 -61
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +2173 -645
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +213 -38
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +416 -36
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +15 -8
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/text.d.ts +32 -0
- package/dist/src/modules/workspace/text.d.ts.map +1 -0
- package/dist/src/modules/workspace/text.js +67 -0
- package/dist/src/modules/workspace/text.js.map +1 -0
- package/dist/src/modules/workspace/types.d.ts +210 -6
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +3 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts +52 -24
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +26 -1
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +164 -39
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +23 -4
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +11 -0
- package/dist/src/send-tools.d.ts.map +1 -0
- package/dist/src/send-tools.js +11 -0
- package/dist/src/send-tools.js.map +1 -0
- package/dist/src/tool-result-guard.d.ts +4 -3
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +5 -4
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +1 -1
- package/dist/src/tool-result-history.js +1 -1
- package/dist/src/tune-out/coordinator.d.ts +21 -0
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +139 -37
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +4 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +62 -9
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +62 -58
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +40 -8
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +111 -10
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/types.d.ts +16 -0
- package/dist/src/usage/types.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +14 -1
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +81 -41
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +6 -5
- package/src/agent.ts +93 -12
- package/src/api/server.ts +14 -12
- package/src/code-execution/engine.ts +595 -0
- package/src/code-execution/index.ts +5 -17
- package/src/code-execution/isolate/calls.ts +199 -0
- package/src/code-execution/isolate/child-entry.ts +5 -0
- package/src/code-execution/isolate/child-main.ts +132 -0
- package/src/code-execution/isolate/child.ts +327 -0
- package/src/code-execution/isolate/frames.ts +209 -0
- package/src/code-execution/isolate/output.ts +161 -0
- package/src/code-execution/isolate/prelude.ts +409 -0
- package/src/code-execution/isolate/protocol.ts +240 -0
- package/src/code-execution/isolate/render.ts +230 -0
- package/src/code-execution/isolate/runner.ts +911 -0
- package/src/code-execution/isolate/scripts.ts +479 -0
- package/src/code-execution/quickjs.wasm +0 -0
- package/src/code-execution/quickjs.wasm.LICENSES +149 -0
- package/src/code-execution/tool-definition.ts +236 -167
- package/src/deadline-timer.ts +1 -1
- package/src/framework.ts +4468 -2418
- package/src/gate/event-gate.ts +78 -11
- package/src/held-writes.ts +17 -3
- package/src/index.ts +30 -22
- package/src/mcpl/channel-registry.ts +1825 -368
- package/src/mcpl/conversation-router.ts +12 -7
- package/src/mcpl/convert-block.ts +9 -5
- package/src/mcpl/inbound-source.ts +131 -0
- package/src/mcpl/index.ts +4 -2
- package/src/mcpl/log-value.ts +9 -0
- package/src/mcpl/modern-connection.ts +162 -53
- package/src/mcpl/prose-grammar.ts +4 -5
- package/src/mcpl/protocol-family.ts +199 -21
- package/src/mcpl/push-coalescer.ts +306 -62
- package/src/mcpl/push-handler.ts +10 -2
- package/src/mcpl/reference-fetcher.ts +4 -4
- package/src/mcpl/server-connection.ts +180 -79
- package/src/mcpl/tags.ts +36 -0
- package/src/mcpl/tool-result-normalize.ts +2 -1
- package/src/mcpl/transport.ts +162 -33
- package/src/mcpl/types.ts +23 -6
- package/src/module-registry.ts +92 -13
- package/src/modules/discord/index.ts +8 -13
- package/src/modules/history/index.ts +25 -3
- package/src/modules/history/semantic.ts +29 -6
- package/src/modules/index.ts +1 -0
- package/src/modules/unknown-tool.ts +4 -1
- package/src/modules/workspace/branch-intent.ts +3 -1
- package/src/modules/workspace/edit-plan.ts +954 -0
- package/src/modules/workspace/edit-text.ts +618 -0
- package/src/modules/workspace/effects.ts +70 -19
- package/src/modules/workspace/index.ts +2247 -642
- package/src/modules/workspace/observe.ts +465 -56
- package/src/modules/workspace/reconcile.ts +14 -7
- package/src/modules/workspace/text.ts +68 -0
- package/src/modules/workspace/types.ts +211 -6
- package/src/modules/workspace/watcher.ts +3 -2
- package/src/operator-log.ts +47 -19
- package/src/recovery/discord-awareness-outbox.ts +1500 -356
- package/src/recovery/offline-branch.ts +189 -55
- package/src/recovery/recover-cli.ts +25 -4
- package/src/send-tools.ts +11 -0
- package/src/tool-result-guard.ts +6 -5
- package/src/tool-result-history.ts +1 -1
- package/src/tune-out/coordinator.ts +163 -42
- package/src/types/agent.ts +4 -0
- package/src/types/events.ts +62 -9
- package/src/types/framework.ts +62 -58
- package/src/types/module.ts +40 -8
- package/src/types/trace.ts +121 -15
- package/src/usage/types.ts +16 -0
- package/src/usage/usage-tracker.ts +86 -43
- package/dist/src/code-execution/py-runner.d.ts +0 -191
- package/dist/src/code-execution/py-runner.d.ts.map +0 -1
- package/dist/src/code-execution/py-runner.js +0 -655
- package/dist/src/code-execution/py-runner.js.map +0 -1
- package/dist/src/code-execution/runtime-py.d.ts +0 -50
- package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
- package/dist/src/code-execution/runtime-py.js +0 -677
- package/dist/src/code-execution/runtime-py.js.map +0 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
- package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
- package/dist/src/mcpl/prose-stream-router.js +0 -291
- package/dist/src/mcpl/prose-stream-router.js.map +0 -1
- package/src/code-execution/py-runner.ts +0 -791
- package/src/code-execution/runtime-py.ts +0 -677
- package/src/mcpl/prose-stream-router.ts +0 -268
|
@@ -68,10 +68,10 @@ import {
|
|
|
68
68
|
|
|
69
69
|
import { StdioTransport, type McplTransport } from './transport.js';
|
|
70
70
|
import { McplProtocolVersionError, McplRequestError, McplUnreapedLaunchError } from './server-connection.js';
|
|
71
|
-
import { LEGACY_MCP_PROTOCOL_VERSION, MAX_TIMER_MS, MODERN_MCP_PROTOCOL_VERSION, checkServerConfig, describeCredentialError, noteDialSent, redactServerText, serverTextRedactor } from './protocol-family.js';
|
|
71
|
+
import { LEGACY_MCP_PROTOCOL_VERSION, MAX_TIMER_MS, MODERN_MCP_PROTOCOL_VERSION, checkServerConfig, describeCredentialError, maskedError, noteDialSent, redactServerText, redactedData, serverTextRedactor, type ServerTextRedactor } from './protocol-family.js';
|
|
72
72
|
import type { McplServerConfig, McpToolDefinition } from './types.js';
|
|
73
73
|
import { boundedForLog } from './errors.js';
|
|
74
|
-
import { logDetail, logValue, logValueRedacted } from './log-value.js';
|
|
74
|
+
import { logDetail, logValue, logValueRedacted, loggedCode } from './log-value.js';
|
|
75
75
|
|
|
76
76
|
const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
|
|
77
77
|
/** Bound on establishing the connection (`server/discover`), like the legacy
|
|
@@ -132,6 +132,12 @@ class NotWrittenError extends Error {
|
|
|
132
132
|
* transport inside the caller's async chain, so the scope reaches `send`. */
|
|
133
133
|
const wireScope = new AsyncLocalStorage<WireRecord>();
|
|
134
134
|
|
|
135
|
+
/** A send in flight, its transport, and what that transport reported
|
|
136
|
+
* meanwhile, held until the send settles (ObservedTransport.send). A
|
|
137
|
+
* scope that names no transport, a notification's or a settled send's,
|
|
138
|
+
* holds nothing. */
|
|
139
|
+
const sendScope = new AsyncLocalStorage<{ wire: ObservedTransport | null; held: Error[] }>();
|
|
140
|
+
|
|
135
141
|
/**
|
|
136
142
|
* The boundary between the SDK and the actual transport. It records, for the
|
|
137
143
|
* logical request in scope, each request of the observed method that it
|
|
@@ -172,15 +178,35 @@ class ObservedTransport implements Transport {
|
|
|
172
178
|
if (record) wireScope.run(record, () => this.onmessage?.(message, extra));
|
|
173
179
|
else this.onmessage?.(message, extra);
|
|
174
180
|
};
|
|
175
|
-
|
|
181
|
+
// An error this transport reports while one of its sends is in flight
|
|
182
|
+
// waits for that send to settle: the SDK's HTTP send reports a failure
|
|
183
|
+
// here and then throws it, and whoever sent it reports what it throws
|
|
184
|
+
// (#556). Anything else is reported at once, another transport's report
|
|
185
|
+
// made in a send's async context too.
|
|
186
|
+
this.inner.onerror = (error) => {
|
|
187
|
+
const sending = sendScope.getStore();
|
|
188
|
+
if (sending?.wire === this) sending.held.push(error);
|
|
189
|
+
else this.onerror?.(error);
|
|
190
|
+
};
|
|
176
191
|
this.inner.onclose = () => this.onclose?.();
|
|
177
192
|
await this.inner.start();
|
|
178
193
|
}
|
|
179
194
|
|
|
180
195
|
async send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void> {
|
|
196
|
+
if ('method' in message && !('id' in message)) {
|
|
197
|
+
// A notification's sender can swallow what its send throws (the SDK's
|
|
198
|
+
// listen teardown does), so what its transport reports is reported at
|
|
199
|
+
// once, whatever send it was made in.
|
|
200
|
+
await sendScope.run({ wire: null, held: [] }, () => this.inner.send(message, options));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
181
203
|
const record = wireScope.getStore();
|
|
182
204
|
let undo: (() => void) | undefined;
|
|
183
205
|
if (record && 'method' in message && 'id' in message && message.method === record.method) {
|
|
206
|
+
// Every transport writes a message as JSON, so one JSON can't write (a
|
|
207
|
+
// BigInt, a cycle) never leaves this host: it's refused here, before
|
|
208
|
+
// it's marked handed off (#556).
|
|
209
|
+
JSON.stringify(message);
|
|
184
210
|
const prior = { handedOff: record.handedOff, currentId: record.currentId, answer: record.answer, error: record.error };
|
|
185
211
|
// Handed off from here on: past this point nothing proves it unsent,
|
|
186
212
|
// unless the transport says it wrote nothing.
|
|
@@ -194,14 +220,29 @@ class ObservedTransport implements Transport {
|
|
|
194
220
|
Object.assign(record, prior);
|
|
195
221
|
};
|
|
196
222
|
}
|
|
223
|
+
// A request's or a response's sender reports what its send throws: a
|
|
224
|
+
// call through its outcome, the connect through its failure, the SDK
|
|
225
|
+
// through its own report. So what the transport reports meanwhile is held
|
|
226
|
+
// here, and the failure the send threw isn't reported a second time (#556).
|
|
227
|
+
const sending: { wire: ObservedTransport | null; held: Error[] } = { wire: this, held: [] };
|
|
228
|
+
let thrown: unknown;
|
|
197
229
|
try {
|
|
198
|
-
await this.inner.send(message, options);
|
|
230
|
+
await sendScope.run(sending, () => this.inner.send(message, options));
|
|
199
231
|
} catch (error) {
|
|
232
|
+
thrown = error;
|
|
200
233
|
// Refused before any write: this leg never reached the server, so the
|
|
201
234
|
// record is as it was before it. Any other throw (an HTTP send can fail
|
|
202
235
|
// after part of the request went out) leaves it handed off.
|
|
203
236
|
if (error instanceof NotWrittenError) undo?.();
|
|
204
237
|
throw error;
|
|
238
|
+
} finally {
|
|
239
|
+
// Settled: what was held goes on, but for the failure the send threw,
|
|
240
|
+
// and the scope lets go of this transport, which work the send started
|
|
241
|
+
// still carries.
|
|
242
|
+
const { held } = sending;
|
|
243
|
+
sending.wire = null;
|
|
244
|
+
sending.held = [];
|
|
245
|
+
for (const error of held) if (error !== thrown) this.onerror?.(error);
|
|
205
246
|
}
|
|
206
247
|
}
|
|
207
248
|
|
|
@@ -278,8 +319,8 @@ class SpawnerStdioTransport implements Transport {
|
|
|
278
319
|
private readonly onStderr: (line: string) => void,
|
|
279
320
|
/** The child's pipe failed and it outlived SIGKILL too, so the line
|
|
280
321
|
* stays open, owning it (the line's 'unreaped'): `reason` names the
|
|
281
|
-
* pipe's error. */
|
|
282
|
-
private readonly onUnreaped: (reason: string) => void,
|
|
322
|
+
* pipe's error, and `failure` is the reap's. */
|
|
323
|
+
private readonly onUnreaped: (reason: string, failure: Error) => void,
|
|
283
324
|
) {
|
|
284
325
|
this.recorded = serverTextRedactor(config);
|
|
285
326
|
}
|
|
@@ -313,14 +354,20 @@ class SpawnerStdioTransport implements Transport {
|
|
|
313
354
|
line.on('stderr', (text: string) => this.onStderr(text));
|
|
314
355
|
line.on('error', (error: Error) => this.onerror?.(error));
|
|
315
356
|
line.on('close', () => this.onclose?.());
|
|
316
|
-
line.on('unreaped', () => this.onUnreaped(`its stdio pipe failed with ${line.pipeFailure?.message ?? 'an error'}
|
|
357
|
+
line.on('unreaped', (failure: Error) => this.onUnreaped(`its stdio pipe failed with ${line.pipeFailure?.message ?? 'an error'}`, failure));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** The first error on the child's stdin or stdout, once there is one: the
|
|
361
|
+
* line is ending the child then, and writes nothing more to it. */
|
|
362
|
+
get pipeFailure(): Error | undefined {
|
|
363
|
+
return this.line?.pipeFailure;
|
|
317
364
|
}
|
|
318
365
|
|
|
319
366
|
async send(message: JSONRPCMessage): Promise<void> {
|
|
320
367
|
if (!this.line || this.line.closed) throw new NotWrittenError(`MCP server "${this.config.id}" stdio transport is closed`);
|
|
321
368
|
// Once the child's stdin or stdout has failed, the line is ending it and
|
|
322
369
|
// writes nothing more to it, so a message is refused here as not sent.
|
|
323
|
-
const failed = this.
|
|
370
|
+
const failed = this.pipeFailure;
|
|
324
371
|
if (failed) throw new NotWrittenError(`MCP server "${this.config.id}" stdio pipe failed with ${failed.message}`, true);
|
|
325
372
|
this.line.writeLine(JSON.stringify(message));
|
|
326
373
|
}
|
|
@@ -374,6 +421,8 @@ interface Session {
|
|
|
374
421
|
readonly generation: number;
|
|
375
422
|
readonly client: Client;
|
|
376
423
|
readonly wire: ObservedTransport;
|
|
424
|
+
/** Its stdio transport, under `wire`; null over HTTP. */
|
|
425
|
+
readonly stdio: SpawnerStdioTransport | null;
|
|
377
426
|
/** Its transport has closed, whether or not the session was adopted yet. */
|
|
378
427
|
lost: boolean;
|
|
379
428
|
}
|
|
@@ -411,6 +460,13 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
411
460
|
* connect() returns), delivered to the first listener. Bounded: the
|
|
412
461
|
* newest lines are kept. */
|
|
413
462
|
private stderrBacklog: string[] = [];
|
|
463
|
+
private redactor?: ServerTextRedactor;
|
|
464
|
+
|
|
465
|
+
/** The server's text with its configuration's credentials replaced, for
|
|
466
|
+
* the errors this connection hands its caller and its records. */
|
|
467
|
+
private get recorded(): ServerTextRedactor {
|
|
468
|
+
return (this.redactor ??= serverTextRedactor(this.config));
|
|
469
|
+
}
|
|
414
470
|
|
|
415
471
|
private constructor(private readonly config: McplServerConfig) {
|
|
416
472
|
super();
|
|
@@ -470,7 +526,8 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
470
526
|
* While it's true the connection owns that child, so whatever registered
|
|
471
527
|
* it keeps its id held; close() retries the reap. It's settled only once
|
|
472
528
|
* a reap has finished: while a lost session's reap or a close runs, it
|
|
473
|
-
*
|
|
529
|
+
* may not read true yet, so read it once lossReaped() or close() has
|
|
530
|
+
* settled. */
|
|
474
531
|
get holdsUnreapedChild(): boolean {
|
|
475
532
|
return this.unreaped.length > 0;
|
|
476
533
|
}
|
|
@@ -483,10 +540,15 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
483
540
|
}
|
|
484
541
|
|
|
485
542
|
/** A failed generation's cleanup couldn't reap its child: keep owning it,
|
|
486
|
-
* and halt reconnecting until close() settles it.
|
|
487
|
-
|
|
543
|
+
* and halt reconnecting until close() settles it. It's reported as an
|
|
544
|
+
* 'error' at once, unless the caller reports it later itself. */
|
|
545
|
+
private holdUnreaped(session: Session, failure: Error, report = true): void {
|
|
488
546
|
if (this.unreaped.some((held) => held.session === session)) return;
|
|
489
547
|
this.unreaped.push({ session, failure });
|
|
548
|
+
if (report) this.reportUnreaped(failure);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private reportUnreaped(failure: Error): void {
|
|
490
552
|
this.emit('error', new Error(
|
|
491
553
|
`MCP server "${this.id}": ${failure.message}. Not starting another launch while it may still be running; close the connection to retry the reap.`,
|
|
492
554
|
));
|
|
@@ -538,10 +600,16 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
538
600
|
this.reconnectEnabled = false;
|
|
539
601
|
throw error;
|
|
540
602
|
}
|
|
603
|
+
// Any other failure is the SDK's or the transport's: it goes on as its
|
|
604
|
+
// words alone, redacted, since its message can quote the url and its
|
|
605
|
+
// other properties, such as Bun's fetch error's `path` or a wrapper's
|
|
606
|
+
// `cause`, can carry it whole (maskedError). The protocol refusal
|
|
607
|
+
// above was built from redacted words.
|
|
608
|
+
const masked = maskedError(error, this.recorded);
|
|
541
609
|
// A launch that couldn't be reaped halts reconnecting, so no retry
|
|
542
610
|
// will come: the first connect fails, as one without reconnect does.
|
|
543
|
-
if (!this.reconnectEnabled || this.holdsUnreapedChild) throw
|
|
544
|
-
console.error(`MCP server "${this.id}" initial connect failed, will retry:`,
|
|
611
|
+
if (!this.reconnectEnabled || this.holdsUnreapedChild) throw masked;
|
|
612
|
+
console.error(`MCP server "${this.id}" initial connect failed, will retry:`, masked.message);
|
|
545
613
|
this.reconnectAttempts = 1;
|
|
546
614
|
this.emit('connect-failed', { error: (error as Error).message, attempt: 0 });
|
|
547
615
|
this.scheduleReconnect();
|
|
@@ -580,17 +648,19 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
580
648
|
// reopen backs off from the base interval, not from the previous
|
|
581
649
|
// generation's failures.
|
|
582
650
|
this.relistenAttempts = 0;
|
|
583
|
-
const
|
|
651
|
+
const stdio = this.transportKind === 'stdio'
|
|
584
652
|
? new SpawnerStdioTransport(
|
|
585
653
|
this.config,
|
|
586
654
|
(line) => { if (this.isCurrent(generation)) this.deliverStderr(line); },
|
|
587
|
-
// A child whose pipe failed and that outlived SIGKILL: a loss
|
|
588
|
-
//
|
|
589
|
-
//
|
|
590
|
-
// yet:
|
|
591
|
-
(
|
|
655
|
+
// A child whose pipe failed and that outlived SIGKILL: a loss whose
|
|
656
|
+
// launch is already known unreaped, so it's held as the loss is
|
|
657
|
+
// handled (handleLost). During a connect there is no session to lose
|
|
658
|
+
// yet: a connect whose pipe has failed fails, whether or not the SDK
|
|
659
|
+
// resolves it (establish), and its cleanup holds the launch.
|
|
660
|
+
(reason, failure) => { if (this.isCurrent(generation)) this.handleLost(generation, reason, failure); },
|
|
592
661
|
)
|
|
593
|
-
:
|
|
662
|
+
: null;
|
|
663
|
+
const inner: Transport = stdio ?? new StreamableHTTPClientTransport(new URL(this.config.url!), { authProvider: bearerAuth(this.config) });
|
|
594
664
|
const wire = new ObservedTransport(inner);
|
|
595
665
|
|
|
596
666
|
const client = new Client(
|
|
@@ -609,7 +679,7 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
609
679
|
},
|
|
610
680
|
},
|
|
611
681
|
);
|
|
612
|
-
const session: Session = { generation, client, wire, lost: false };
|
|
682
|
+
const session: Session = { generation, client, wire, stdio, lost: false };
|
|
613
683
|
client.onerror = (error: Error) => {
|
|
614
684
|
// The SDK reports late responses to deadline-abandoned calls here
|
|
615
685
|
// ("unknown message ID"), and a list-change subscription it could not
|
|
@@ -654,16 +724,23 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
654
724
|
if (failure) this.holdUnreaped(session, failure);
|
|
655
725
|
return;
|
|
656
726
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
727
|
+
// The transport closed while the client connected, such as a child that
|
|
728
|
+
// exited at the connect-time list-change subscribe, or the child's stdio
|
|
729
|
+
// pipe failed, such as that subscribe's write meeting EPIPE: the SDK
|
|
730
|
+
// reports the subscribe's failure only as an error, and resolves the
|
|
731
|
+
// connect anyway (R1-2). Adopted, the session would read as connected
|
|
732
|
+
// with nothing it can write to behind it, and from a child that outlived
|
|
733
|
+
// SIGKILL, whose 'unreaped' came while there was no session to lose, no
|
|
734
|
+
// later close would come to reconnect it. So the connect failed: its
|
|
735
|
+
// close reaps the child, and a child it can't reap is held. A failed
|
|
736
|
+
// pipe is named whether or not the child has exited by now.
|
|
737
|
+
const pipe = session.stdio?.pipeFailure;
|
|
738
|
+
if (session.lost || pipe) {
|
|
664
739
|
const failure = await ModernMcpConnection.closeSession(session);
|
|
665
740
|
if (failure) this.holdUnreaped(session, failure);
|
|
666
|
-
throw new Error(
|
|
741
|
+
throw new Error(pipe
|
|
742
|
+
? `MCP server "${this.id}" stdio pipe failed with ${pipe.message} while connecting`
|
|
743
|
+
: `MCP server "${this.id}" closed its connection while connecting`);
|
|
667
744
|
}
|
|
668
745
|
this.session = session;
|
|
669
746
|
this.protocolVersion = MODERN_MCP_PROTOCOL_VERSION;
|
|
@@ -679,7 +756,11 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
679
756
|
*/
|
|
680
757
|
private versionVerdict(error: unknown): McplProtocolVersionError | null {
|
|
681
758
|
if (!(error instanceof UnsupportedProtocolVersionError)) return null;
|
|
682
|
-
|
|
759
|
+
// The server's words and data, redacted before they're bounded or kept:
|
|
760
|
+
// the error goes to the host. One build for all of them, so a
|
|
761
|
+
// configuration that can't be read is read once.
|
|
762
|
+
const redact = this.recorded.now();
|
|
763
|
+
const data = redactedData((error as { data?: unknown }).data, redact) as { supported?: unknown } | undefined;
|
|
683
764
|
const supported = Array.isArray(data?.supported) && data.supported.every((v) => typeof v === 'string')
|
|
684
765
|
? (data.supported as string[])
|
|
685
766
|
: null;
|
|
@@ -693,13 +774,13 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
693
774
|
: ` It speaks only legacy MCP, which this client reaches over stdio or WebSocket (ws://, wss://), not http(s).`;
|
|
694
775
|
return new McplProtocolVersionError(
|
|
695
776
|
`MCP server "${this.id}" does not support MCP ${MODERN_MCP_PROTOCOL_VERSION}` +
|
|
696
|
-
(supported ? ` (it supports: ${supported.join(', ') || 'none listed'}).` : ` (${error.message}).`) +
|
|
777
|
+
(supported ? ` (it supports: ${boundedForLog(supported.join(', ')) || 'none listed'}).` : ` (${boundedForLog(redact(error.message))}).`) +
|
|
697
778
|
legacyHint,
|
|
698
779
|
'rejected',
|
|
699
780
|
null,
|
|
700
781
|
supported,
|
|
701
782
|
(error as { code?: unknown }).code === undefined ? undefined : Number((error as { code?: unknown }).code),
|
|
702
|
-
|
|
783
|
+
data,
|
|
703
784
|
MODERN_MCP_PROTOCOL_VERSION,
|
|
704
785
|
);
|
|
705
786
|
}
|
|
@@ -762,8 +843,10 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
762
843
|
}
|
|
763
844
|
}
|
|
764
845
|
|
|
765
|
-
/** The transport went away (child exit, or a closed HTTP client).
|
|
766
|
-
|
|
846
|
+
/** The transport went away (child exit, or a closed HTTP client).
|
|
847
|
+
* `unreaped`: the child's pipe failed and it outlived SIGKILL, so its
|
|
848
|
+
* launch is already known unreaped. */
|
|
849
|
+
private handleLost(generation: number, reason: string, unreaped?: Error): void {
|
|
767
850
|
const session = this.session;
|
|
768
851
|
if (session?.generation !== generation) return;
|
|
769
852
|
this.session = null;
|
|
@@ -775,18 +858,34 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
775
858
|
// reconnect's does, and is a permanent failure, as that one is: no
|
|
776
859
|
// later attempt will come. The reap starts, and is recorded, before
|
|
777
860
|
// 'close' is emitted, so a listener that throws can't skip it.
|
|
861
|
+
const permanent = () => this.emit('reconnect-failed', { error: `${reason}; ${this.unreapedFailure()}`, attempt: Math.max(1, this.reconnectAttempts), permanent: true });
|
|
778
862
|
const done = ModernMcpConnection.closeSession(session).then((failure) => {
|
|
779
863
|
if (this.losing?.session === session) this.losing = null;
|
|
864
|
+
// A close() the host made meanwhile reports the failure itself.
|
|
865
|
+
if (unreaped) {
|
|
866
|
+
// Held as the loss was handled, whatever the reap found now.
|
|
867
|
+
if (!this.closedByHost) permanent();
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
780
870
|
if (failure) {
|
|
781
871
|
this.holdUnreaped(session, failure);
|
|
782
|
-
|
|
783
|
-
if (!this.closedByHost) {
|
|
784
|
-
this.emit('reconnect-failed', { error: `${reason}; ${this.unreapedFailure()}`, attempt: Math.max(1, this.reconnectAttempts), permanent: true });
|
|
785
|
-
}
|
|
872
|
+
if (!this.closedByHost) permanent();
|
|
786
873
|
} else if (this.willReconnect) this.scheduleReconnect();
|
|
787
874
|
});
|
|
788
875
|
this.losing = { session, done };
|
|
789
|
-
|
|
876
|
+
// A launch already known unreaped is held now, before 'close', so the
|
|
877
|
+
// calls the reap's close ends, which classify their failure only once
|
|
878
|
+
// this returns, and any made meanwhile, read that this host won't
|
|
879
|
+
// reconnect, as the legacy engine has it (#540's review, R1-1). It's
|
|
880
|
+
// reported after 'close', which is where the other route reports a hold
|
|
881
|
+
// too, whatever the 'close' listeners do, so a listener that throws can
|
|
882
|
+
// skip neither 'close' nor the report.
|
|
883
|
+
if (unreaped) this.holdUnreaped(session, unreaped, false);
|
|
884
|
+
try {
|
|
885
|
+
this.emit('close', { reason });
|
|
886
|
+
} finally {
|
|
887
|
+
if (unreaped) this.reportUnreaped(unreaped);
|
|
888
|
+
}
|
|
790
889
|
}
|
|
791
890
|
|
|
792
891
|
/** The legacy engine's backoff: doubling from the base interval, capped,
|
|
@@ -1013,9 +1112,9 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
1013
1112
|
* The rules apply in this order. The call's answer is the server's final
|
|
1014
1113
|
* one: an error or a `complete` result.
|
|
1015
1114
|
* - nothing handed to the transport: `not-sent`, whatever was raised (a
|
|
1016
|
-
* pre-dispatch validation, a signal already aborted, no transport, a
|
|
1017
|
-
* Connectome's stdio line refused
|
|
1018
|
-
*
|
|
1115
|
+
* pre-dispatch validation, a signal already aborted, no transport, a
|
|
1116
|
+
* message JSON can't write, a send Connectome's stdio line refused
|
|
1117
|
+
* before writing);
|
|
1019
1118
|
* - the most recent leg answered with a JSON-RPC error: `error-response`
|
|
1020
1119
|
* with that error's data;
|
|
1021
1120
|
* - the most recent leg answered with a complete result: the server
|
|
@@ -1051,7 +1150,10 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
1051
1150
|
private requestFailure(what: string, record: WireRecord, error: unknown, timeoutMs?: number, lost = false): Error {
|
|
1052
1151
|
const server = `the "${this.id}" server`;
|
|
1053
1152
|
const Server = `The "${this.id}" server`;
|
|
1054
|
-
|
|
1153
|
+
// One build of the redactor for all of this failure's texts, so a
|
|
1154
|
+
// configuration that can't be read is read once.
|
|
1155
|
+
const redact = this.recorded.now();
|
|
1156
|
+
const message = redact(error instanceof Error ? error.message : String(error));
|
|
1055
1157
|
const log = (line: string) => console.error(`MCP server "${this.id}" ${line}`);
|
|
1056
1158
|
const listing = record.method === 'tools/list';
|
|
1057
1159
|
// What a failure whose effect is in doubt says: for a tool call, that the
|
|
@@ -1075,18 +1177,21 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
1075
1177
|
}
|
|
1076
1178
|
if (record.answer === 'error' && record.error) {
|
|
1077
1179
|
const { code, message: wireMessage, data } = record.error;
|
|
1078
|
-
//
|
|
1079
|
-
//
|
|
1080
|
-
//
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
//
|
|
1084
|
-
//
|
|
1085
|
-
|
|
1180
|
+
// The log is a record of the server's text, so the code (loggedCode)
|
|
1181
|
+
// and the message are redacted there, whatever JSON values they are,
|
|
1182
|
+
// as every other line this connection writes is.
|
|
1183
|
+
log(`answered ${what} with error ${loggedCode(code, redact)}: ${logValueRedacted(wireMessage, redact)}`);
|
|
1184
|
+
// The server's own words, redacted and then bounded as errors.ts says,
|
|
1185
|
+
// since they're in an error the caller gets (redactServerText's
|
|
1186
|
+
// scope), and its data's strings redacted too. It's trimmed after it's
|
|
1187
|
+
// redacted, so a credential that ends in a space is whole when it's
|
|
1188
|
+
// matched. Only a string is words: a message of any other JSON value
|
|
1189
|
+
// reads as none.
|
|
1190
|
+
const said = typeof wireMessage === 'string' ? boundedForLog(redact(wireMessage).trim()) : '';
|
|
1086
1191
|
return new McplRequestError(
|
|
1087
1192
|
said ? `${Server} answered with an error: ${said}` : unknown(`${Server} answered with an error without saying what went wrong`),
|
|
1088
1193
|
'error-response',
|
|
1089
|
-
data,
|
|
1194
|
+
redactedData(data, redact),
|
|
1090
1195
|
);
|
|
1091
1196
|
}
|
|
1092
1197
|
if (record.answer === 'complete') {
|
|
@@ -1132,10 +1237,14 @@ export class ModernMcpConnection extends EventEmitter {
|
|
|
1132
1237
|
// The response body (the SDK's `text`) is the server's text and can
|
|
1133
1238
|
// echo the request's url, so it's left out of the data; the status stays.
|
|
1134
1239
|
const { text: _body, ...data } = (error instanceof SdkHttpError && error.data && typeof error.data === 'object' ? error.data : {}) as Record<string, unknown>;
|
|
1240
|
+
const redacted = redactedData(data, redact);
|
|
1135
1241
|
return new McplRequestError(
|
|
1136
1242
|
`${Server} refused this host access, so the request didn't run. If you need it, ask whoever runs this host.`,
|
|
1137
1243
|
'error-response',
|
|
1138
|
-
|
|
1244
|
+
// The status is this host's own, so it's added after the server's
|
|
1245
|
+
// data is redacted, and it stays when a configuration that can't be
|
|
1246
|
+
// read withholds that data.
|
|
1247
|
+
{ ...(redacted !== null && typeof redacted === 'object' ? redacted : {}), httpStatus: refusedWith },
|
|
1139
1248
|
);
|
|
1140
1249
|
}
|
|
1141
1250
|
if (deadline) {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Explicit-prose routing grammar
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* on what is a prefix, what is a modifier, and what is body.
|
|
2
|
+
* Explicit-prose routing grammar: the prefix parsers the delivery path uses
|
|
3
|
+
* (parseProsePrefix, parseHybridProsePrefix). The envelope splitters in
|
|
4
|
+
* framework.ts test a line's `>>` or `>>>` start on their own. The outgoing
|
|
5
|
+
* stream needs no parser of its own: it carries what delivery publishes.
|
|
7
6
|
*
|
|
8
7
|
* Grammar (docs/explicit-prose-routing.md):
|
|
9
8
|
* `>>target [!] [body…]` — target = channel spec or `skip_reply`
|