docs: clean up ADR-005 architecture docs after envelope implementation
Remove stale ADR-005 drift tables across all architecture docs since ResponseEnvelope types, factories, detection, and integration points are now fully implemented in source code. Key changes: - api-surface.md: Remove ADR-005 drift table (all items implemented), retain ADR-006 drift table without execute() return type (now done) - call-protocol.md: Remove ADR-005 drift table, update ADR-006 table, fix CallHandlerConfig to show callMap? (current source) - adapters.md: Remove 'current source state' and 'implementation changes needed' tables for from_mcp and from_openapi, replace with current-accurate descriptions of envelope behavior - response-envelopes.md: Remove 'current source state' blocks, update migration checklist to show all code changes completed - 005-response-envelopes.md: Change status from Draft to Implemented - 006-unified-invocation-path.md: Update Prerequisites section to note ADR-005 is now implemented - build-distribution.md: Add response-envelope.ts to source layout - architecture.md: Add response-envelopes.md link and ADR-005/006 entries to design decisions table - README.md: Add response-envelopes.md to documents table - Update last_updated dates on all changed docs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-09
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# @alkdev/operations Architecture
|
||||
@@ -74,6 +74,7 @@ Spokes will import `@alkdev/operation` for operation definitions and `@alkdev/pu
|
||||
|----------|---------|
|
||||
| [api-surface.md](api-surface.md) | All public types, registry, call protocol, subscribe, env, adapters |
|
||||
| [call-protocol.md](call-protocol.md) | PendingRequestMap, CallHandler, call≡subscribe, events, error model, access control |
|
||||
| [response-envelopes.md](response-envelopes.md) | Response envelope types, factory functions, detection, schemas, integration points |
|
||||
| [adapters.md](adapters.md) | from_schema, from_openapi, from_mcp, scanner — how they work, how to add new adapters |
|
||||
| [build-distribution.md](build-distribution.md) | Dependencies, project structure, sub-path exports, peer deps, build tooling |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-09
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# Adapters
|
||||
@@ -79,13 +79,7 @@ Processes all paths in the spec. For each path and method combination:
|
||||
- Applies auth headers from config
|
||||
- Returns JSON, text, or `ArrayBuffer` based on response content type
|
||||
|
||||
**Current source state** (`src/from_openapi.ts`): The handler currently returns raw response data — `response.json()`, `response.text()`, or `response.arrayBuffer()` (lines 273-279). It does NOT wrap the result in `httpEnvelope()`. Error handling throws a plain `Error` (line 268) instead of `CallError`. The response-envelopes spec requires wrapping in `httpEnvelope()` and throwing `CallError` on HTTP errors. The `Value.Cast()` normalization step against `outputSchema` is also not yet implemented. See [response-envelopes.md](response-envelopes.md) for the full specification.
|
||||
|
||||
| What | Current source (`src/from_openapi.ts`) | Target (per response-envelopes spec) |
|
||||
|------|------------------------------------------|---------------------------------------|
|
||||
| Handler return value | Returns raw `response.json()` / `.text()` / `.arrayBuffer()` (lines 273-279) | Returns `httpEnvelope(data, { statusCode, headers, contentType })` |
|
||||
| Error handling | Throws `Error(\`HTTP ${status}\`)` (line 268) | Throws `CallError("EXECUTION_ERROR", ...)` |
|
||||
| `Value.Cast()` | Not used | If `outputSchema !== Unknown`, cast `Value.Cast(outputSchema, data)` |
|
||||
The handler wraps results in `httpEnvelope()` with HTTP metadata (status code, headers, content type). On HTTP error status, it throws `CallError("EXECUTION_ERROR", ...)`. `Value.Cast()` normalization against `outputSchema` is applied by `registry.execute()` and `CallHandler` as part of the shared result pipeline — see [response-envelopes.md](response-envelopes.md#shared-result-pipeline).
|
||||
|
||||
### `FromOpenAPIFile(path, config, fs?)`
|
||||
|
||||
@@ -179,11 +173,11 @@ async function createMCPClient(
|
||||
- `namespace`: the `name` parameter (used as grouping)
|
||||
- `type`: `MUTATION` (all MCP tools are mutations)
|
||||
### `FromSchema(tool.inputSchema)` (converts JSON Schema to TypeBox)
|
||||
- `outputSchema`: `tool.outputSchema ? FromSchema(tool.outputSchema) : Type.Unknown()` (MCP spec 2025-06-18+ provides `outputSchema`; older tools lack it)
|
||||
- `handler`: calls `client.callTool({ name, arguments })`, wraps result in `mcpEnvelope()`
|
||||
- `accessControl`: `{ requiredScopes: [] }` (no auth by default)
|
||||
- `outputSchema`: `tool.outputSchema ? FromSchema(tool.outputSchema) : Type.Unknown()` (MCP spec 2025-06-18+ provides `outputSchema`; older tools lack it)
|
||||
- `handler`: calls `client.callTool({ name, arguments })`, wraps result in `mcpEnvelope()`
|
||||
- `accessControl`: `{ requiredScopes: [] }` (no auth by default)
|
||||
|
||||
**Current source state** (`src/from_mcp.ts` line 66): `outputSchema: Type.Unknown()` for all tools. The `tool.outputSchema` property is not used. The handler currently throws on `isError` (line 76) and returns `result.content` directly (line 79) instead of wrapping in `mcpEnvelope()`. The `structuredContent` field on `CallToolResult` is not used. See [response-envelopes.md](response-envelopes.md) for the full specification of what needs to change.
|
||||
The handler returns pre-built `ResponseEnvelope` instances via `mcpEnvelope()`. `isError: true` results are wrapped in the envelope (not thrown), so consumers check `envelope.meta.isError`. `structuredContent` is preferred as `envelope.data` when available; otherwise `mapMCPContentBlocks(result.content)` is used. `Value.Cast()` normalization against `outputSchema` is applied by `registry.execute()` and `CallHandler` as part of the shared result pipeline.
|
||||
|
||||
### outputSchema and structuredContent
|
||||
|
||||
@@ -203,17 +197,7 @@ When a tool does NOT declare `outputSchema`:
|
||||
|
||||
See [response-envelopes.md](response-envelopes.md) for the full envelope specification and envelope stripping with `Value.Cast()`.
|
||||
|
||||
**Implementation changes needed** (tracking spec vs. current source):
|
||||
|
||||
| What | Current source (`src/from_mcp.ts`) | Target (per response-envelopes spec) |
|
||||
|------|--------------------------------------|---------------------------------------|
|
||||
| `outputSchema` at discovery | `Type.Unknown()` for all tools (line 66) | `tool.outputSchema ? FromSchema(tool.outputSchema) : Type.Unknown()` |
|
||||
| Handler return value | Returns `result.content` (line 79) | Returns `mcpEnvelope(data, meta)` |
|
||||
| `structuredContent` | Not used | Prefer as `data` when present; fall back to `mapMCPContentBlocks(result.content)` |
|
||||
| `isError` handling | Throws `Error` (line 76) | Wraps in envelope with `meta.isError: true`, does NOT throw |
|
||||
| `Value.Cast()` | Not used | If `structuredContent && outputSchema !== Unknown`, cast `Value.Cast(outputSchema, structuredContent)` |
|
||||
|
||||
The `CallToolResult` type in the installed SDK (`@modelcontextprotocol/sdk` DRAFT-2026-v1) already includes `structuredContent?: { [key: string]: unknown }` and the `Tool` type already includes `outputSchema?`. No SDK upgrade needed — only the adapter code needs updating.
|
||||
The `CallToolResult` type in the installed SDK (`@modelcontextprotocol/sdk` DRAFT-2026-v1) includes `structuredContent?: { [key: string]: unknown }` and the `Tool` type includes `outputSchema?`. The adapter code extracts `outputSchema` at discovery time and uses `structuredContent` at call time.
|
||||
|
||||
### `MCPClientConfig`
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-10
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# API Surface
|
||||
@@ -373,23 +373,7 @@ See [adapters.md](adapters.md) for detailed adapter documentation.
|
||||
|
||||
## Source vs. Spec Drift
|
||||
|
||||
This section documents differences between the architecture spec (this document) and the current source code. Items marked **ADR-005** or **ADR-006** are planned changes not yet implemented.
|
||||
|
||||
### ADR-005 (Response Envelopes) — not yet implemented
|
||||
|
||||
| What | Spec says | Source currently does |
|
||||
|------|----------|----------------------|
|
||||
| `ResponseEnvelope`, `ResponseMeta`, factory functions, `isResponseEnvelope()`, `unwrap()` | Exported from `src/response-envelope.ts` | None of these types or functions exist in source |
|
||||
| `execute()` return type | `Promise<ResponseEnvelope<TOutput>>` | `Promise<TOutput>` |
|
||||
| `execute()` result pipeline | Detect → wrap → normalize → validate | Returns raw `result`, validates raw output with `collectErrors` |
|
||||
| `OperationEnv` inner function return type | `Promise<ResponseEnvelope>` | `Promise<unknown>` |
|
||||
| `PendingRequestMap.call()` return type | `Promise<ResponseEnvelope>` | `Promise<unknown>` |
|
||||
| `PendingRequestMap.respond()` validation | Enforces `isResponseEnvelope()`, throws on raw values | Accepts `unknown`, no validation |
|
||||
| `subscribe()` yield type | `AsyncGenerator<ResponseEnvelope, void, unknown>` | `AsyncGenerator<unknown, void, unknown>` |
|
||||
| `CallRespondedEvent.output` | `ResponseEnvelope` | `unknown` |
|
||||
| `CallHandler` description | Wraps handler result, applies pipeline, publishes `call.responded` | Discards handler return value; handler publishes `call.responded` itself |
|
||||
| `from_mcp` handler | Returns `mcpEnvelope()`, uses `structuredContent`, extracts `outputSchema` | Returns `result.content`, types `outputSchema` as `Type.Unknown()`, throws on `isError` |
|
||||
| `from_openapi` handler | Returns `httpEnvelope()` with HTTP metadata | Returns raw response data, throws on HTTP error status |
|
||||
This section documents differences between the architecture spec and the current source code. ADR-005 (Response Envelopes) has been fully implemented — all envelope types, factories, detection, and integration points are in source and match the spec. ADR-006 (Unified Invocation Path) is not yet implemented.
|
||||
|
||||
### ADR-006 (Unified Invocation Path) — not yet implemented
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-09
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# Build & Distribution
|
||||
@@ -43,6 +43,7 @@ Dependencies, project structure, sub-path exports, peer deps, and build tooling.
|
||||
types.ts # Core types: IOperationDefinition, OperationSpec, OperationType, etc.
|
||||
registry.ts # OperationRegistry: registerSpec, registerHandler, execute, get, list
|
||||
validation.ts # assertIsSchema, validateOrThrow, collectErrors, formatValueErrors
|
||||
response-envelope.ts # ResponseEnvelope types, factories, detection, schemas, unwrap
|
||||
call.ts # PendingRequestMap, buildCallHandler, CallEventMap, event types
|
||||
subscribe.ts # subscribe(): direct AsyncGenerator execution
|
||||
env.ts # buildEnv(): namespace-keyed env with direct/call-protocol modes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-10
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# Call Protocol
|
||||
@@ -159,7 +159,7 @@ function buildCallHandler(config: CallHandlerConfig): CallHandler
|
||||
|
||||
interface CallHandlerConfig {
|
||||
registry: OperationRegistry
|
||||
eventTarget?: EventTarget
|
||||
callMap?: PendingRequestMap
|
||||
}
|
||||
|
||||
type CallHandler = (event: CallRequestedEvent) => Promise<void>
|
||||
@@ -309,20 +309,7 @@ This allows spec-only registration for scenarios where handlers are provided sep
|
||||
|
||||
## Source vs. Spec Drift
|
||||
|
||||
This section documents differences between the architecture spec (this document) and the current source code. Items are planned changes not yet implemented.
|
||||
|
||||
### ADR-005 (Response Envelopes) — not yet implemented
|
||||
|
||||
| What | Spec says | Source currently does |
|
||||
|------|----------|----------------------|
|
||||
| `CallEventSchema["call.responded"].output` | `ResponseEnvelopeSchema` | `Type.Unknown()` |
|
||||
| `CallHandler` behavior | Wraps handler return value, publishes `call.responded` | Discards handler return value; handler must publish itself |
|
||||
| `CallHandler` error handling | Publishes `call.error` via pubsub | Re-throws `CallError` (does not publish) |
|
||||
| `call()` return type | `Promise<ResponseEnvelope>` | `Promise<unknown>` |
|
||||
| `call()` resolution | Resolves with `ResponseEnvelope` from `output` field | Resolves with raw `unknown` from `output` |
|
||||
| `respond()` validation | Enforces `isResponseEnvelope()` guard, throws on raw values | Accepts `unknown`, no validation |
|
||||
| `subscribe()` yield type | `AsyncGenerator<ResponseEnvelope, void, unknown>`, wraps yields | `AsyncGenerator<unknown, void, unknown>`, yields raw values |
|
||||
| `buildEnv()` return types | `Promise<ResponseEnvelope>` per function | `Promise<unknown>` per function |
|
||||
This section documents differences between the architecture spec (this document) and the current source code. ADR-005 (Response Envelopes) has been fully implemented — `CallEventSchema["call.responded"].output` uses `ResponseEnvelopeSchema`, `CallHandler` wraps handler return values and publishes `call.responded`, `call()` returns `Promise<ResponseEnvelope>`, `respond()` enforces `isResponseEnvelope()`, `subscribe()` yields `ResponseEnvelope`, and `buildEnv()` returns `Promise<ResponseEnvelope>` per function. ADR-006 (Unified Invocation Path) is not yet implemented.
|
||||
|
||||
### ADR-006 (Unified Invocation Path) — not yet implemented
|
||||
|
||||
@@ -333,7 +320,6 @@ This section documents differences between the architecture spec (this document)
|
||||
| `CallHandler` calls `execute()` | Thin adapter that calls `registry.execute()` internally | Reimplements lookup, validation, and access control independently |
|
||||
| `buildEnv()` | Always uses `execute()`, no `callMap` option | Toggles between `execute()` and `callMap.call()` via `if (callMap)` |
|
||||
| `OperationContext.trusted` | New field for nested call bypass | Does not exist |
|
||||
| `execute()` return type | `Promise<ResponseEnvelope<TOutput>>` | `Promise<TOutput>` |
|
||||
| `execute()` error type | Throws `CallError` | Throws plain `Error` |
|
||||
|
||||
## References
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ADR-005: Response Envelopes for Transport-Aware Results
|
||||
|
||||
**Status**: Draft
|
||||
**Status**: Implemented
|
||||
**Date**: 2026-05-10
|
||||
|
||||
## Context
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-10
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# ADR-006: Unified Invocation Path
|
||||
@@ -31,7 +31,7 @@ Meanwhile `execute()` is a **domain call** — same-process, same-trust, rich ty
|
||||
|
||||
### Prerequisites
|
||||
|
||||
This ADR depends on ADR-005 (response envelopes) being implemented in source first. The unified `execute()` requires `ResponseEnvelope` types, `isResponseEnvelope()`, and factory functions that don't exist in source yet.
|
||||
This ADR depends on ADR-005 (response envelopes) being implemented in source first. **ADR-005 is now implemented** — `ResponseEnvelope` types, `isResponseEnvelope()`, and factory functions exist in `src/response-envelope.ts`. The prerequisite is met.
|
||||
|
||||
## Decision
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-10
|
||||
last_updated: 2026-05-11
|
||||
---
|
||||
|
||||
# Response Envelopes
|
||||
@@ -221,15 +221,6 @@ Flow:
|
||||
|
||||
**Note**: `isResponseEnvelope()` does not validate that the envelope's `source` matches the operation's origin. An MCP handler that explicitly returns a `localEnvelope(...)` passes through as-is. Handlers that explicitly construct envelopes take responsibility for their metadata.
|
||||
|
||||
**Current source state** (`src/registry.ts` lines 80-105): `execute()` returns `Promise<TOutput>` directly. It does not wrap results in envelopes, does not call `isResponseEnvelope()`, and validates raw `result` against `outputSchema`. The `Value.Cast()` normalization step is not implemented. Changes needed:
|
||||
|
||||
| What | Current source | Target |
|
||||
|------|---------------|--------|
|
||||
| Return type | `Promise<TOutput>` | `Promise<ResponseEnvelope<TOutput>>` |
|
||||
| Wrapping | None — returns raw `result` | `isResponseEnvelope(result) ? result : localEnvelope(result, operationId)` |
|
||||
| Validation | `collectErrors(spec.outputSchema, result)` — on raw value | `collectErrors(spec.outputSchema, envelope.data)` — on envelope data |
|
||||
| `Value.Cast()` | Not used | If `outputSchema !== Unknown`, `envelope.data = Value.Cast(spec.outputSchema, envelope.data)` |
|
||||
|
||||
### `CallHandler`
|
||||
|
||||
Takes full ownership of publishing `call.responded`. Handlers return values; they do NOT publish events.
|
||||
@@ -246,29 +237,14 @@ Flow:
|
||||
9. Publish `call.responded` via `callMap.respond(requestId, envelope)`
|
||||
10. On handler exception → publish `call.error` (existing). Note: an envelope with `meta.isError: true` does **not** trigger `call.error`. Only thrown exceptions do.
|
||||
|
||||
**Current source state** (`src/call.ts` lines 182-233): `buildCallHandler` calls `handler(input, context)` (line 226) but does not use the return value. The handler is expected to publish `call.responded` itself. Changes needed:
|
||||
|
||||
| What | Current source | Target |
|
||||
|------|---------------|--------|
|
||||
| Handler model | Handler publishes `call.responded` itself; return value ignored | Handler returns value; `CallHandler` wraps and publishes |
|
||||
| Return value | `await handler(input, context)` called but result discarded | Result captured, wrapped in envelope if needed, then published |
|
||||
| Envelope detection | Not applicable | `isResponseEnvelope(result)` check before wrapping |
|
||||
| Result pipeline | None | Detect → wrap → normalize → validate → publish |
|
||||
| `call.responded.output` | `Type.Unknown()` | `ResponseEnvelopeSchema` |
|
||||
| `PendingRequestMap.respond()` | Accepts any `unknown` value | Must enforce `isResponseEnvelope()` guard |
|
||||
|
||||
### `PendingRequestMap.respond()`
|
||||
|
||||
Enforces that `output` is a `ResponseEnvelope` via the `isResponseEnvelope()` type guard (not full schema validation). If called with a non-envelope value, throws. This prevents any code bypassing `CallHandler`'s envelope wrapping. A future iteration may make `respond()` internal (not exported on the public API surface) to further enforce this invariant.
|
||||
|
||||
**Current source state** (`src/call.ts` lines 151-156): `respond()` publishes `call.responded` with `output: unknown`. No envelope validation.
|
||||
|
||||
### `PendingRequestMap.call()`
|
||||
|
||||
Resolves with the `ResponseEnvelope` from `call.responded.output` instead of raw `unknown`.
|
||||
|
||||
**Current source state** (`src/call.ts` lines 120-149): `call()` returns `Promise<unknown>`. The type should become `Promise<ResponseEnvelope>`.
|
||||
|
||||
### `subscribe()`
|
||||
|
||||
Each yielded value is wrapped in `ResponseEnvelope`. `SubscriptionHandler` implementations still yield raw values — `subscribe()` wraps each yield, consistent with how local handlers return raw values and `execute()` wraps them. If a yielded value `isResponseEnvelope()`, it passes through. Otherwise, `localEnvelope(value, operationId)` with a fresh `timestamp` per yield.
|
||||
@@ -455,26 +431,24 @@ The following documentation changes have been completed:
|
||||
| `api-surface.md` | `CallHandler` | Wraps handler result, publishes `call.responded`. No longer "handler publishes" model. | ✅ |
|
||||
| `call-protocol.md` | `PendingRequestMap.respond()` | Now enforces `isResponseEnvelope()` check — throws on raw values. | ✅ |
|
||||
| `api-surface.md` | `PendingRequestMap.respond()` | `respond()` now requires `ResponseEnvelope` argument. | ✅ |
|
||||
| `adapters.md` | `from_mcp` | Handler returns `mcpEnvelope()`. MCP `isError: true` no longer throws. | ✅ (previous) |
|
||||
| `adapters.md` | `from_mcp` | `outputSchema` extracted when available, via `FromSchema`. Falls back to `Type.Unknown()`. | ✅ (previous) |
|
||||
| `adapters.md` | `from_openapi` | Handler returns `httpEnvelope()`. Error on HTTP error status still throws `CallError`. | ✅ (previous) |
|
||||
| `adapters.md` | `from_mcp` | Handler returns `mcpEnvelope()`. MCP `isError: true` no longer throws. | ✅ |
|
||||
| `adapters.md` | `from_mcp` | `outputSchema` extracted when available, via `FromSchema`. Falls back to `Type.Unknown()`. | ✅ |
|
||||
| `adapters.md` | `from_openapi` | Handler returns `httpEnvelope()`. Error on HTTP error status still throws `CallError`. | ✅ |
|
||||
|
||||
The following **code** changes are still needed:
|
||||
The following **code** changes have been completed:
|
||||
|
||||
| Code | Change |
|
||||
|------|--------|
|
||||
| `src/registry.ts` | `execute()` returns `Promise<ResponseEnvelope<TOutput>>` |
|
||||
| `src/call.ts` | `CallHandler` captures return value, wraps in envelope, publishes `call.responded` |
|
||||
| `src/call.ts` | `CallEventSchema` `output` field changes to `ResponseEnvelopeSchema` |
|
||||
| `src/call.ts` | `PendingRequestMap.respond()` adds `isResponseEnvelope()` guard |
|
||||
| `src/call.ts` | `PendingRequestMap.call()` resolves with `ResponseEnvelope` |
|
||||
| `src/subscribe.ts` | `subscribe()` wraps yields in `ResponseEnvelope` |
|
||||
| `src/env.ts` | `buildEnv()` functions return `Promise<ResponseEnvelope>` |
|
||||
| `src/response-envelope.ts` | New file: types, factory functions, detection, schemas |
|
||||
| `src/from_mcp.ts` | Handler returns `mcpEnvelope()`, extracts `outputSchema`, uses `structuredContent` |
|
||||
| `src/from_openapi.ts` | Handler returns `httpEnvelope()` |
|
||||
|
||||
Additionally, any code subscribing to `"call.responded"` events via the pubsub system (not just `PendingRequestMap`, but any direct pubsub consumer) must expect `ResponseEnvelope` instead of `unknown` in the event payload.
|
||||
| Code | Change | Status |
|
||||
|------|--------|--------|
|
||||
| `src/response-envelope.ts` | New file: types, factory functions, detection, schemas | ✅ |
|
||||
| `src/registry.ts` | `execute()` returns `Promise<ResponseEnvelope<TOutput>>` | ✅ |
|
||||
| `src/call.ts` | `CallHandler` captures return value, wraps in envelope, publishes `call.responded` | ✅ |
|
||||
| `src/call.ts` | `CallEventSchema` `output` field changes to `ResponseEnvelopeSchema` | ✅ |
|
||||
| `src/call.ts` | `PendingRequestMap.respond()` adds `isResponseEnvelope()` guard | ✅ |
|
||||
| `src/call.ts` | `PendingRequestMap.call()` resolves with `ResponseEnvelope` | ✅ |
|
||||
| `src/subscribe.ts` | `subscribe()` wraps yields in `ResponseEnvelope` | ✅ |
|
||||
| `src/env.ts` | `buildEnv()` functions return `Promise<ResponseEnvelope>` | ✅ |
|
||||
| `src/from_mcp.ts` | Handler returns `mcpEnvelope()`, extracts `outputSchema`, uses `structuredContent` | ✅ |
|
||||
| `src/from_openapi.ts` | Handler returns `httpEnvelope()` | ✅ |
|
||||
|
||||
## References
|
||||
|
||||
|
||||
Reference in New Issue
Block a user