nexus-ai-pro 2.21.0 → 2.22.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.
Files changed (158) hide show
  1. package/API_STABILITY.md +63 -0
  2. package/CHANGELOG.md +133 -1
  3. package/README.md +6 -2
  4. package/SECURITY.md +16 -2
  5. package/dist/agent/openapi.d.ts +94 -8
  6. package/dist/agent/openapi.js +528 -32
  7. package/dist/core/secure-stream.js +4 -1
  8. package/dist/decisions/completion.js +2 -2
  9. package/dist/decisions/typesafe.d.ts +11 -3
  10. package/dist/decisions/typesafe.js +28 -9
  11. package/dist/embeddings/adapters.d.ts +1 -1
  12. package/dist/embeddings/adapters.js +3 -3
  13. package/dist/embeddings/batch-google.d.ts +27 -8
  14. package/dist/embeddings/batch-google.js +112 -36
  15. package/dist/embeddings/batch-mock.js +1 -1
  16. package/dist/embeddings/batch.js +10 -4
  17. package/dist/embeddings/engine.js +14 -13
  18. package/dist/embeddings/index.d.ts +1 -1
  19. package/dist/embeddings/inputs.d.ts +26 -3
  20. package/dist/embeddings/inputs.js +84 -5
  21. package/dist/embeddings/mock.js +1 -1
  22. package/dist/embeddings/models.js +39 -4
  23. package/dist/loaders/csv.d.ts +23 -1
  24. package/dist/loaders/csv.js +125 -72
  25. package/dist/loaders/index.d.ts +7 -2
  26. package/dist/loaders/input.d.ts +6 -0
  27. package/dist/loaders/input.js +42 -1
  28. package/dist/loaders/json.d.ts +14 -3
  29. package/dist/loaders/json.js +171 -20
  30. package/dist/loaders/web.d.ts +55 -0
  31. package/dist/loaders/web.js +20 -1
  32. package/dist/mcp/client.d.ts +54 -5
  33. package/dist/mcp/client.js +171 -20
  34. package/dist/mcp/http.d.ts +45 -0
  35. package/dist/mcp/http.js +233 -0
  36. package/dist/mcp/index.d.ts +4 -2
  37. package/dist/mcp/index.js +3 -1
  38. package/dist/mcp/protocol.d.ts +107 -0
  39. package/dist/mcp/sampling.d.ts +41 -0
  40. package/dist/mcp/sampling.js +52 -0
  41. package/dist/mcp/server.d.ts +96 -14
  42. package/dist/mcp/server.js +274 -59
  43. package/dist/models/data.js +20 -1
  44. package/dist/protocols/a2a-grpc.js +10 -3
  45. package/dist/protocols/a2a-signing.d.ts +65 -0
  46. package/dist/protocols/a2a-signing.js +133 -0
  47. package/dist/protocols/a2a.d.ts +14 -0
  48. package/dist/protocols/a2a.js +44 -8
  49. package/dist/providers/cohere.js +16 -2
  50. package/dist/providers/google.js +7 -1
  51. package/dist/providers/ollama.d.ts +1 -1
  52. package/dist/providers/ollama.js +35 -27
  53. package/dist/providers/openai.js +6 -2
  54. package/dist/rag/pinecone.d.ts +63 -2
  55. package/dist/rag/pinecone.js +80 -0
  56. package/dist/realtime/conversation.js +18 -0
  57. package/dist/realtime/gemini-live.transport.d.ts +28 -3
  58. package/dist/realtime/gemini-live.transport.js +170 -32
  59. package/dist/realtime/session.d.ts +2 -0
  60. package/dist/realtime/session.js +19 -4
  61. package/dist/realtime/types.d.ts +35 -3
  62. package/dist/security/output-guard.js +4 -1
  63. package/dist/server/auth.d.ts +263 -2
  64. package/dist/server/auth.js +432 -5
  65. package/dist/telephony/index.d.ts +1 -1
  66. package/dist/telephony/manager.d.ts +8 -1
  67. package/dist/telephony/manager.js +13 -0
  68. package/dist/telephony/providers/telnyx.d.ts +18 -5
  69. package/dist/telephony/providers/telnyx.js +44 -7
  70. package/dist/telephony/providers/twilio.d.ts +3 -1
  71. package/dist/telephony/providers/twilio.js +16 -0
  72. package/dist/types/embeddings.d.ts +47 -5
  73. package/dist/types/messages.d.ts +7 -0
  74. package/dist/types/principal.d.ts +1 -1
  75. package/dist/types/response.d.ts +5 -0
  76. package/dist/types/telephony.d.ts +38 -0
  77. package/dist/version.d.ts +1 -1
  78. package/dist/version.js +1 -1
  79. package/dist/voice/providers/google.d.ts +44 -0
  80. package/dist/voice/providers/google.js +215 -0
  81. package/dist-cjs/agent/openapi.d.ts +94 -8
  82. package/dist-cjs/agent/openapi.js +530 -32
  83. package/dist-cjs/core/secure-stream.js +4 -1
  84. package/dist-cjs/decisions/completion.js +2 -2
  85. package/dist-cjs/decisions/typesafe.d.ts +11 -3
  86. package/dist-cjs/decisions/typesafe.js +28 -9
  87. package/dist-cjs/embeddings/adapters.d.ts +1 -1
  88. package/dist-cjs/embeddings/adapters.js +3 -3
  89. package/dist-cjs/embeddings/batch-google.d.ts +27 -8
  90. package/dist-cjs/embeddings/batch-google.js +112 -36
  91. package/dist-cjs/embeddings/batch-mock.js +1 -1
  92. package/dist-cjs/embeddings/batch.js +9 -3
  93. package/dist-cjs/embeddings/engine.js +13 -12
  94. package/dist-cjs/embeddings/index.d.ts +1 -1
  95. package/dist-cjs/embeddings/inputs.d.ts +26 -3
  96. package/dist-cjs/embeddings/inputs.js +89 -5
  97. package/dist-cjs/embeddings/mock.js +1 -1
  98. package/dist-cjs/embeddings/models.js +39 -4
  99. package/dist-cjs/loaders/csv.d.ts +23 -1
  100. package/dist-cjs/loaders/csv.js +126 -71
  101. package/dist-cjs/loaders/index.d.ts +7 -2
  102. package/dist-cjs/loaders/input.d.ts +6 -0
  103. package/dist-cjs/loaders/input.js +43 -1
  104. package/dist-cjs/loaders/json.d.ts +14 -3
  105. package/dist-cjs/loaders/json.js +170 -19
  106. package/dist-cjs/loaders/web.d.ts +55 -0
  107. package/dist-cjs/loaders/web.js +21 -1
  108. package/dist-cjs/mcp/client.d.ts +54 -5
  109. package/dist-cjs/mcp/client.js +171 -20
  110. package/dist-cjs/mcp/http.d.ts +45 -0
  111. package/dist-cjs/mcp/http.js +236 -0
  112. package/dist-cjs/mcp/index.d.ts +4 -2
  113. package/dist-cjs/mcp/index.js +5 -1
  114. package/dist-cjs/mcp/protocol.d.ts +107 -0
  115. package/dist-cjs/mcp/sampling.d.ts +41 -0
  116. package/dist-cjs/mcp/sampling.js +55 -0
  117. package/dist-cjs/mcp/server.d.ts +96 -14
  118. package/dist-cjs/mcp/server.js +273 -58
  119. package/dist-cjs/models/data.js +20 -1
  120. package/dist-cjs/protocols/a2a-grpc.js +10 -3
  121. package/dist-cjs/protocols/a2a-signing.d.ts +65 -0
  122. package/dist-cjs/protocols/a2a-signing.js +140 -0
  123. package/dist-cjs/protocols/a2a.d.ts +14 -0
  124. package/dist-cjs/protocols/a2a.js +49 -9
  125. package/dist-cjs/providers/cohere.js +16 -2
  126. package/dist-cjs/providers/google.js +7 -1
  127. package/dist-cjs/providers/ollama.d.ts +1 -1
  128. package/dist-cjs/providers/ollama.js +35 -27
  129. package/dist-cjs/providers/openai.js +6 -2
  130. package/dist-cjs/rag/pinecone.d.ts +63 -2
  131. package/dist-cjs/rag/pinecone.js +81 -0
  132. package/dist-cjs/realtime/conversation.js +18 -0
  133. package/dist-cjs/realtime/gemini-live.transport.d.ts +28 -3
  134. package/dist-cjs/realtime/gemini-live.transport.js +170 -32
  135. package/dist-cjs/realtime/session.d.ts +2 -0
  136. package/dist-cjs/realtime/session.js +19 -4
  137. package/dist-cjs/realtime/types.d.ts +35 -3
  138. package/dist-cjs/security/output-guard.js +4 -1
  139. package/dist-cjs/server/auth.d.ts +263 -2
  140. package/dist-cjs/server/auth.js +437 -5
  141. package/dist-cjs/telephony/index.d.ts +1 -1
  142. package/dist-cjs/telephony/manager.d.ts +8 -1
  143. package/dist-cjs/telephony/manager.js +13 -0
  144. package/dist-cjs/telephony/providers/telnyx.d.ts +18 -5
  145. package/dist-cjs/telephony/providers/telnyx.js +44 -7
  146. package/dist-cjs/telephony/providers/twilio.d.ts +3 -1
  147. package/dist-cjs/telephony/providers/twilio.js +16 -0
  148. package/dist-cjs/types/embeddings.d.ts +47 -5
  149. package/dist-cjs/types/messages.d.ts +7 -0
  150. package/dist-cjs/types/principal.d.ts +1 -1
  151. package/dist-cjs/types/response.d.ts +5 -0
  152. package/dist-cjs/types/telephony.d.ts +38 -0
  153. package/dist-cjs/version.d.ts +1 -1
  154. package/dist-cjs/version.js +1 -1
  155. package/dist-cjs/voice/providers/google.d.ts +44 -0
  156. package/dist-cjs/voice/providers/google.js +252 -0
  157. package/llms.txt +1 -1
  158. package/package.json +17 -1
package/API_STABILITY.md CHANGED
@@ -67,6 +67,69 @@ graduation:
67
67
  | Upgrade | A migration test from the previous minor |
68
68
  | Soak | A long-running test with flat memory and no leaked handles |
69
69
 
70
+ ## 2.22 stage (2.22.0)
71
+
72
+ Everything 2.22 adds is stable from the start and additive, unless this section says otherwise.
73
+
74
+ New and stable: `StreamChunk.logprobs`; in `nexus-ai-pro/protocols/a2a`, `signA2aCard()`,
75
+ `verifyA2aCard()`, `canonicalA2aCard()`, `A2aCardSignatureError`, `A2aCardSigner`, `A2aCardKeyResolver`,
76
+ `A2aSignatureAlgorithm`, `A2aJsonWebKey`, `A2aCryptoKey`, `A2aServerOptions.sign`, and
77
+ `A2aClientOptions.verifyCard`, which `A2aGrpcClientOptions` takes too; in `nexus-ai-pro/mcp`,
78
+ `mcpHttpHandler()`, `McpHttpOptions`, `McpHttpHandler`, `samplingFrom()`, `McpSamplingOptions`,
79
+ `McpSamplingClient`, `McpServerPrompt`, `McpPromptArgument`, `McpPromptMessage`, `McpServerResource`,
80
+ the server's `registerPrompt()`, `registerResource()`, `resourceUpdated()`, `createMessage()`,
81
+ `elicit()`, `listRoots()`, and `onRootsChanged()`, the client's `sampling`, `elicitation`, and `roots`
82
+ options, `onPromptsChanged()`, `onResourcesChanged()`, `onResourceUpdated()`, `subscribeResource()`,
83
+ `unsubscribeResource()`, and `rootsChanged()`, `HttpClientOptions.listen`, the protocol types
84
+ `McpSamplingRequest`, `McpSamplingResult`, `McpSamplingMessage`, `McpSamplingContent`,
85
+ `McpModelPreferences`, `McpElicitationRequest`, `McpElicitationResult`, `McpRoot`, and
86
+ `McpCallerRequests`, and `ToolContext.mcp`; in `nexus-ai-pro/agent/openapi`, `swaggerToOpenApi()`,
87
+ `bundleOpenApiDocument()`, `OpenApiBundleOptions`, `OpenApiCredential`, `OpenApiWebhook`,
88
+ `OpenApiToolsOptions.credentials`, `OpenApiOperation.security`, `OpenApiTools.webhooks`, and
89
+ `loadOpenApiTools()`'s `references`, `maxDocuments`, and `maxBytes`; in `nexus-ai-pro/server/auth`,
90
+ `createJwtSigner()`, `JwtSigner`, `JwtSignerOptions`, `JwtSignOptions`, `generateJwtKey()`,
91
+ `jwksHandler()`, `createApiKeyStore()`, `ApiKeyStore`, `ApiKeyStoreOptions`, `ApiKeyRecord`,
92
+ `IssuedApiKey`, `ApiKeyIssueOptions`, `createSessions()`, `Sessions`, `SessionOptions`,
93
+ `SessionCookieOptions`, `SessionRecord`, and `StartedSession`, and the principal method `session`; in
94
+ `nexus-ai-pro/rag/pinecone`, `PineconeVectorStore.create()`, `ensurePineconeIndex()`,
95
+ `PineconeIndexOptions`, `PineconeIndex`, and `PineconeCreateOptions`, experimental with the store;
96
+ `TypeSafeDecisionProviderOptions.pictures`; and in `nexus-ai-pro/embeddings`, `EmbeddingVideoPart`, the
97
+ modality `video`, `EmbeddingMeta.unpricedMedia`, and `EmbeddingModelCapabilities`'
98
+ `costPerAudioSecond`, `costPerVideoFrame`, `videoFrames`, `maxAudioSeconds`, and `maxVideoSeconds`; in
99
+ the loaders, `FileInput`'s stream form, `CsvRowParser`, `JsonLoaderOptions.recordsAt`,
100
+ `WebLoaderOptions.render` and `renderBelow`, `browserRenderer()`, `WebPageRenderer`, `WebPageToRender`,
101
+ `RenderingBrowser`, and `BrowserRendererOptions`; in the realtime family, `ImageItem`, the `message.image`
102
+ event, and `RealtimeConversationOptions.recordImages`; in telephony, `TelephonyGatherResult`,
103
+ `EndGatherRequest`, `parseGatherResult()` and `endGather()` on the manager and the providers, and
104
+ `TelnyxTelephonyProviderConfig.transcriptionEngine`; in the studio, `StudioOptions.tenantSources`,
105
+ `StudioUser.tenant`, `StudioAuditEntry.tenant`, `StudioComment.tenant`, `StudioAuditQuery`,
106
+ `HeaderAuthOptions.tenant`, `BearerAuthOptions.tenant`, `StudioSignIn`, and `StudioOptions.signIn`.
107
+ Experimental: in the studio, `oidcSignIn()`, `OidcSignInOptions`, `SIGN_IN_COOKIE`, and the
108
+ `/auth/` routes, until a sign-in against a live provider is recorded; `nexus-ai-pro/voice/google`,
109
+ `GoogleVoiceProvider` and `GoogleVoiceProviderConfig`, until a live run is recorded.
110
+ The state store keys and sessions are kept in, under `nexus/server`, is read by every later 2.x.
111
+
112
+ Changed on purpose: an answer the output guard changes or blocks keeps no `logprobs`, streamed or
113
+ not; a typed decision of a model that reports the chosen token alone is sampled; an Ollama stream
114
+ honours `stop`. An MCP server declares prompts and resource subscriptions at `initialize` whatever it
115
+ was given, and serves every transport connected to it rather than the last; a tool it runs gets a
116
+ `signal` and `mcp` in its context. The HTTP client transport returns from `send()` before a streamed
117
+ answer ends, sends `mcp-protocol-version`, and sends a `DELETE` when closed with a session. OpenAPI
118
+ tools are made of operations with any request body, where those with a body other than JSON or a form
119
+ were skipped, and of Swagger 2.0 documents, which were refused; `loadOpenApiTools()` reads no more of
120
+ a document than `maxBytes`. With `credentials` given, an operation whose security cannot be met fails
121
+ before it is sent.
122
+
123
+ A TypeSafe AI request with pictures is multipart unless `pictures: 'base64'`, and its size is counted
124
+ in bytes. gemini-embedding-2's audio and video are priced, where they cost nothing before, and audio
125
+ past 180 seconds or video past 120 is refused before the call. A Google embedding batch over 20 MB is
126
+ sent as a file, where it was refused. Gemini Live acts on `updateSession()`, which it ignored. A
127
+ realtime record holds the images sent, as `image` items, which a consumer that switches on every item
128
+ type meets for the first time. A Telnyx gather for speech transcribes the caller, where it was
129
+ refused.
130
+
131
+ Deprecated: `OpenApiTools.skipped`, always empty, is removed in 3.0.
132
+
70
133
  ## 2.21 stage (2.21.0)
71
134
 
72
135
  Everything 2.21 adds is stable from the start and additive, unless this section says otherwise.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,137 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.22.0] - 2026-10-29
8
+
9
+ MCP over streamable HTTP both ways, OpenAPI tools that send each operation's credentials, tokens, keys,
10
+ and sessions the server issues, and a studio that signs people in and serves many tenants; with signed
11
+ A2A cards, embeddings of video, loaders that stream, Gemini's voice, and the kernel in Firefox and
12
+ WebKit.
13
+
14
+ ### Added
15
+
16
+ - **Log probabilities from a stream.** Each `text` chunk's `StreamChunk.logprobs` holds its tokens'
17
+ log probabilities, from OpenAI's Chat Completions and Responses API, Gemini, Ollama, and Cohere, so
18
+ the chunks' together are what `complete()` reports.
19
+ - Cohere reports log probabilities, `complete()` and streamed: a piece of text at a time, each piece's
20
+ the sum of its tokens', with no alternatives.
21
+ - **MCP both ways.** A server offers prompts (`McpServerPrompt`, `registerPrompt()`), resources a client
22
+ subscribes to (`resourceUpdated()`), and tells every client each list's changes; a tool it runs may ask
23
+ the client that called it for a completion from its model, an answer from its person, or its roots,
24
+ through `context.mcp`, and is stopped when the client cancels it. A client answers a server's
25
+ `sampling`, `elicitation`, and `roots` with handlers of its own, `samplingFrom()` answering with
26
+ the application's own model, and hears each list change and each resource it subscribed to.
27
+ - **MCP over streamable HTTP, both ways.** `mcpHttpHandler()` serves an `McpServer` as a Web handler:
28
+ a session per client, a stream of events per request carrying the server's progress and questions
29
+ before its answer, a `GET` stream for what it sends of its own accord, `DELETE` to end a session, and
30
+ a request from another origin refused. The client's HTTP transport reads a stream as it comes, so a
31
+ question in the middle of a call arrives in time, listens on a `GET` stream with `listen`, sends the
32
+ protocol version, and ends its session on `close()`. The nightly interoperability run drives the
33
+ server with `@modelcontextprotocol/sdk`'s own client: its tools, a completion asked mid-call, its
34
+ progress, a prompt, and a subscribed resource's change.
35
+ - **Signed A2A cards.** `signA2aCard()` and `verifyA2aCard()`, with `canonicalA2aCard()`, sign and check
36
+ a card as protocol 1.0 does, a flattened JWS over its canonical form, which is the A2A project's SDK's
37
+ form: a card either signs, the other verifies. A handler's `sign` signs every card it serves, each
38
+ tenant's and the extended card included, and a client's `verifyCard` makes no call until a signature
39
+ on the card holds. ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384, PS512, and Ed25519, by the
40
+ Web Crypto API alone. The nightly interoperability run checks both directions against `@a2a-js/sdk`.
41
+ - **OpenAPI credentials.** Tools read from an OpenAPI document send the credentials each operation's
42
+ security asks for, from `credentials` given by scheme name, or chosen per call: an API key in a
43
+ header, query parameter, or cookie; HTTP Basic, bearer, or another HTTP scheme; and an OAuth 2.0 or
44
+ OpenID Connect token, held, or fetched by the client-credentials flow for the operation's scopes and
45
+ kept until a minute before it expires. An operation whose alternatives none can be met fails before
46
+ anything is sent, naming them. Each `OpenApiOperation` carries its `security`.
47
+ - **Swagger 2.0, and references to other documents.** A Swagger 2.0 document is read as the OpenAPI 3.0
48
+ one it describes, which `swaggerToOpenApi()` returns. `bundleOpenApiDocument()` reads in the other
49
+ documents a document's references name, on its own origin by default, or as `references` allows,
50
+ within `maxDocuments` and `maxBytes`; `loadOpenApiTools()` does so itself.
51
+ - OpenAPI tools send a multipart form, its file fields given as base64, a text or XML body, and a body
52
+ of bytes, such as an image, so every operation becomes a tool. `webhooks` lists what the API sends
53
+ the application, its webhooks and its operations' callbacks, each with its JSON body's schema.
54
+ - **Tokens, keys, and sessions the server issues.** `createJwtSigner()` issues tokens with a secret, a
55
+ PEM or JWK private key, or a Web Crypto key pair, and `issue()` writes a principal under the claim
56
+ names `jwtAuth()` reads back; `generateJwtKey()` makes a key, and `jwksHandler()` publishes the
57
+ public halves, for a rotation that refuses no live token. `createApiKeyStore()` issues, rotates with
58
+ a grace period, and revokes API keys, kept as hashes in the server's state store with when each was
59
+ last used. `createSessions()` signs browsers in after a sign-in of the application's own: an
60
+ `HttpOnly`, `Secure`, `SameSite=Lax` cookie of a random secret whose hash alone is kept, an idle
61
+ and a total lifetime, sign-out here or everywhere, and a request from another site's page refused.
62
+ - **A Pinecone store makes its own index.** `PineconeVectorStore.create()` creates a serverless index
63
+ with the cosine metric and the store's width, or uses one of that name that fits, waits until it is
64
+ ready, and returns a store over its host; `ensurePineconeIndex()` does the first part alone.
65
+ - TypeSafe AI is sent a decision's pictures as parts of a multipart request, as bytes, so three
66
+ pictures of 10 MiB fit in the 32 MiB a request holds; `TypeSafeDecisionProviderOptions.pictures`
67
+ set to `base64` sends them within the JSON, as before.
68
+ - **Embeddings of video, and audio and video priced by length.** An `EmbeddingVideoPart` holds a video
69
+ by its bytes, base64, or a URL, such as a Files API URI, and gemini-embedding-2 embeds it. Audio is
70
+ priced by the second and video by the frame the model takes, one a second and at most 32 on
71
+ gemini-embedding-2, at $0.00016 a second and $0.00079 a frame, each length read from the media's own
72
+ headers; a budget counts them before the call. Media longer than a model's `maxAudioSeconds` or
73
+ `maxVideoSeconds` is refused before it is sent, and media whose length cannot be read is counted in
74
+ `unpricedMedia`. A registry data file sets these prices and limits too, each checked when it loads.
75
+ - A Google embedding batch over 20 MB, up to 2 GB, is uploaded as a JSONL file through the Files API, and
76
+ its results are read from the file the batch writes, matched to their inputs by key.
77
+ - **CSV and JSON stream through.** `loadCsv()` and `loadJson()` read a file as it arrives and yield each
78
+ row or record as soon as it is read: a path in chunks, or a `FileInput` that is now also a stream,
79
+ such as a response's body. `CsvRowParser` parses CSV a piece at a time, and `recordsAt` names the
80
+ array of records inside a JSON document, such as `data.items`, read item by item. A file larger than
81
+ memory goes to the store a batch at a time.
82
+ - **Pages built by script.** `loadWebPages()` takes a `render` of the application's own for a page
83
+ whose text a script builds, and `browserRenderer()` makes one from a Playwright or Puppeteer browser,
84
+ with no browser a dependency of the package.
85
+ - **Gemini voice.** `GoogleVoiceProvider`, on `nexus-ai-pro/voice/google`, speaks in Gemini's voices, as
86
+ WAV or raw PCM, whichever its model answers with, directed by a system instruction that is never
87
+ spoken; and transcribes with a text model that hears the audio, inline or by a Files API URI, guided
88
+ by its language and the names it may hold. Experimental until a live run is recorded.
89
+ - **Gemini Live changes its setup mid-call.** `updateSession()` on Gemini Live sets the session up again
90
+ between turns, on a new socket resumed from the latest handle: instructions, voice, language,
91
+ modalities, tools, turn detection, the model, and Gemini's own setup fields. What is sent meanwhile
92
+ waits, and the conversation carries on.
93
+ - **Images in the realtime record.** An image sent in a realtime conversation is kept as an `ImageItem`,
94
+ with its digest and, unless `recordImages` is `digest`, the image, and a resumed session gives it
95
+ back to the model. Video frames are not kept.
96
+ - **Telnyx gathers speech.** A gather that listens for speech on Telnyx transcribes the caller's side of
97
+ the call, with its prompts spoken and keys still taken, until `endGather()`. `parseGatherResult()`
98
+ reads what a gather collected on either provider, Twilio's `SpeechResult` and `Digits` or Telnyx's
99
+ `call.transcription` and `call.gather.ended`, as one `TelephonyGatherResult`.
100
+ - **The studio signs people in, and serves many tenants.** `oidcSignIn()` signs people in with any
101
+ OpenID Connect provider, with no proxy in front: the code flow with PKCE, a state, and a nonce, the ID
102
+ token verified against the provider's keys, and a signed session cookie that replicas share, with
103
+ sign-out at the provider too. A person's `tenant`, from a claim, a header, or the users file, picks
104
+ the sources they read, from `tenantSources`; they see their tenant's comments and audit entries
105
+ alone, and their page token is bound to it.
106
+ - **The kernel in Firefox and WebKit.** The portable kernel's own tests, the file Node.js, Deno, Bun,
107
+ and the edge runtime run, now run in a browser page too, in headless Chromium on every build and in
108
+ Firefox and WebKit, Safari's engine, in CI, with a graph, an agent with a streaming tool, and AG-UI.
109
+ - **Cohere's Embed 5.** `embed-v5.0-pro` and `embed-v5.0-fast` are in the registry, with their
110
+ sizes from 256 to 2,048, 128,000 tokens, and images. Cohere publishes no per-token price for them,
111
+ so they are registered without one.
112
+
113
+ ### Changed
114
+
115
+ - A TypeSafe AI request with pictures is multipart by default, and its 32 MiB is counted in bytes, not
116
+ characters, so a state of text outside ASCII is refused before it is sent rather than by the API.
117
+ - `loadCsv()` and `loadJson()` yield their first document before the rest of the file is read; a JSON
118
+ file whose array of records is cut short is refused as such, after the records before the cut.
119
+ - An OpenAPI operation with a multipart or other non-JSON body becomes a tool, where it was skipped; a
120
+ Swagger 2.0 document is read, where it was refused; and `loadOpenApiTools()` refuses a document over
121
+ `maxBytes`, 5 MB by default, reading no further.
122
+
123
+ ### Deprecated
124
+
125
+ - `OpenApiTools.skipped`, always empty now that every operation becomes a tool. It is removed in 3.0.
126
+
127
+ ### Fixed
128
+
129
+ - **An answer the output guard redacts keeps no log probabilities.** They name the tokens the model
130
+ wrote, so a redacted address or connection string was still spelled out in `response.logprobs`; now
131
+ they are dropped wherever the guard changes or blocks the text, streamed or not.
132
+ - The Google embedding batch adapter reads inline results under the name Google's API reference gives
133
+ them, `inlinedResponses`, as well as its clients' name.
134
+ - A typed decision asked of a model that reports only the chosen token's log probability, with no
135
+ alternatives, is sampled, where it was read as certain.
136
+ - An Ollama stream stops at the request's `stop` sequences, as a call does.
137
+
7
138
  ## [2.21.0] - 2026-10-26
8
139
 
9
140
  Typed decisions about pictures, compatibility records gathered from community adapters' own CI, and
@@ -3361,7 +3492,8 @@ shared policy vocabulary is in place for a future release that revisits this.
3361
3492
  - URL fetching rejects unsafe private-network targets and limits response reads.
3362
3493
  - CLI and audit findings no longer disclose detected secret values.
3363
3494
 
3364
- [Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.21.0...HEAD
3495
+ [Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.22.0...HEAD
3496
+ [2.22.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.21.0...v2.22.0
3365
3497
  [2.21.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.20.2...v2.21.0
3366
3498
  [2.20.2]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.20.1...v2.20.2
3367
3499
  [2.20.1]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.20.0...v2.20.1
package/README.md CHANGED
@@ -341,11 +341,15 @@ Shipped so far:
341
341
  evaluated with nothing sent, and one A2A handler serving many tenants, each seeing only its own;
342
342
  - 2.21 typed decisions about pictures, a yes or no, a choice, a score, or a box around something in
343
343
  one, from TypeSafe AI's Jev or any vision model; community adapters' compatibility records gathered
344
- from their own CI, a failing one turning red; and 3.0's defaults behind one switch today.
344
+ from their own CI, a failing one turning red; and 3.0's defaults behind one switch today;
345
+ - 2.22 MCP over streamable HTTP both ways, with prompts, resources, and a server's questions back to
346
+ the client; OpenAPI tools that send each operation's credentials; tokens, API keys, and sessions the
347
+ server issues; and a studio that signs people in with your identity provider and serves many
348
+ tenants, each seeing only its own.
345
349
 
346
350
  Upgrading from 1.x: `npx nexus migrate src --write` moves your imports, and
347
351
  [MIGRATING.md](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/MIGRATING.md) covers the rest.
348
- Next, in 2.22, Pinecone, images, the Gemini embedding batch tier, media understanding, video, typed
352
+ Next, in 2.23, Pinecone, images, the Gemini embedding batch tier, media understanding, video, typed
349
353
  decisions, Gemini Live, SIP, and both phone providers graduate once the live workflow passes against
350
354
  each. The
351
355
  [roadmap](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/ROADMAP.md) lists what comes after, in the order
package/SECURITY.md CHANGED
@@ -281,9 +281,23 @@ Findings, each fixed in 2.5 with a test in `studio/test/security.test.ts`:
281
281
  - **A proposal's pull-request link was rendered as stored.** The content security policy already
282
282
  blocked a `javascript:` address. Only `http` and `https` links are rendered now.
283
283
 
284
+ Signing in and tenants, reviewed for 2.22, with tests in `studio/test/signin.test.ts` and
285
+ `studio/test/tenants.test.ts`:
286
+ - The provider's configuration must name the issuer the studio was given. An ID token must verify
287
+ against the provider's keys, name that issuer and the studio's client as its audience, and carry
288
+ the sign-in's nonce; a token for several clients must name the studio as `azp`.
289
+ - The state, nonce, and PKCE verifier travel in a cookie signed for that purpose alone, for ten
290
+ minutes, so a callback from another browser, a late one, or a changed one is refused, and a sign-in
291
+ cookie is never taken as a session.
292
+ - The page to come back to is always a path on the studio, never another site.
293
+ - A tenant's people read only what `tenantSources` gives for their tenant. The studio itself keeps
294
+ comments and audit entries to their tenant, whatever the store does, and binds the page token to it.
295
+ `headerAuth()` with a tenant header refuses a request that lacks it.
296
+
284
297
  Documented limitations, which the studio guide states:
285
- - The studio has no tenants of its own. Every account sees every source the studio is given, so a
286
- tenant's people get a studio over that tenant's `tenantScope()` views.
298
+ - Someone without a tenant reads the studio's own sources, the operators' view.
299
+ - A session is a signed cookie, so one person's cannot be ended before it expires; rotating the
300
+ sign-in secret signs everyone out. Signing out is a plain link, which another site can follow.
287
301
  - A page token stays valid while the secret, the user, and their role do. Rotate `secret` to revoke
288
302
  every page at once.
289
303
  - Someone without a session who opens another person's personal link is signed in as that person.
@@ -44,6 +44,38 @@ export interface OpenApiOperation {
44
44
  tags: string[];
45
45
  /** What it does to the service, read from its method: `read` for GET, HEAD, OPTIONS, and TRACE, `destructive` for DELETE, and `write` for the rest. */
46
46
  access: 'read' | 'write' | 'destructive';
47
+ /**
48
+ * The security it asks for, as the document writes it: alternatives, any one of which will do, each
49
+ * the schemes it needs at once with their scopes. Empty when it asks for none.
50
+ */
51
+ security: Array<Record<string, string[]>>;
52
+ }
53
+ /**
54
+ * A credential for one of the API's security schemes: the API key, bearer token, or access token as
55
+ * text or `{ token }`; `{ username, password }` for HTTP basic; or `{ clientId, clientSecret }` for an
56
+ * OAuth 2.0 client-credentials flow, whose token is fetched and kept until it expires.
57
+ */
58
+ export type OpenApiCredential = string | {
59
+ token: string;
60
+ } | {
61
+ username: string;
62
+ password: string;
63
+ } | {
64
+ clientId: string;
65
+ clientSecret: string;
66
+ };
67
+ /** A request or callback the API sends to the application, which no tool calls: its name and the body it carries. */
68
+ export interface OpenApiWebhook {
69
+ /** The webhook's name, or the operation and callback it belongs to. */
70
+ name: string;
71
+ /** `webhook` for one of the document's webhooks, `callback` for an operation's callback. */
72
+ source: 'webhook' | 'callback';
73
+ /** The HTTP method it arrives with, in capitals. */
74
+ method: string;
75
+ /** For a callback, the expression that names where it is sent, such as `{$request.body#/callbackUrl}`. */
76
+ expression?: string;
77
+ /** The JSON Schema of the body it carries, when it carries JSON. */
78
+ body?: Record<string, unknown>;
47
79
  }
48
80
  /** What a tool's headers are chosen from: the operation, and the call's context. */
49
81
  export interface OpenApiHeadersRequest {
@@ -79,6 +111,15 @@ export interface OpenApiToolsOptions {
79
111
  maxResponseBytes?: number;
80
112
  /** Replaces the global `fetch`. */
81
113
  fetch?: typeof globalThis.fetch;
114
+ /**
115
+ * Credentials for the API's own security schemes, by the name the document gives each, or a
116
+ * function choosing one per call, such as by its tenant. Each call sends those its operation asks
117
+ * for: the first of its alternatives every scheme of which has a credential, as an API key in its
118
+ * header, query, or cookie, HTTP basic or bearer, or an OAuth 2.0 or OpenID Connect token. With
119
+ * credentials given, a call whose operation asks for schemes none of which has one fails before it
120
+ * is sent. They win over `headers`.
121
+ */
122
+ credentials?: Readonly<Record<string, OpenApiCredential | ((request: OpenApiHeadersRequest) => OpenApiCredential | Promise<OpenApiCredential>)>>;
82
123
  }
83
124
  /** An API's operations as tools, with what each returns. */
84
125
  export interface OpenApiTools {
@@ -92,19 +133,26 @@ export interface OpenApiTools {
92
133
  operations: OpenApiOperation[];
93
134
  /** The JSON Schema of what each tool returns, by name: its first success response's. Pass it to `emulatedTools()` as `results`. */
94
135
  results: Record<string, Record<string, unknown>>;
95
- /** Operations that could not become tools, and why: a request body of a type the tools do not send. */
136
+ /**
137
+ * Operations that could not become tools, and why.
138
+ *
139
+ * @deprecated Every operation becomes a tool since 2.22, its body sent whatever its type, so this is
140
+ * always empty. It is removed in 3.0.
141
+ */
96
142
  skipped: Array<{
97
143
  method: string;
98
144
  path: string;
99
145
  reason: string;
100
146
  }>;
147
+ /** What the API sends the application, which no tool calls: its webhooks and its operations' callbacks. */
148
+ webhooks: OpenApiWebhook[];
101
149
  }
102
150
  /** Why an API could not be read into tools, or a call to it failed. */
103
151
  export declare class OpenApiError extends Error {
104
152
  /**
105
153
  * `OPENAPI_INVALID` for a malformed document or call, `OPENAPI_UNSUPPORTED` for one these tools
106
- * cannot read, such as Swagger 2.0 or a reference outside the document, and `OPENAPI_REQUEST`
107
- * for a call the API refused or did not answer.
154
+ * cannot read, such as Swagger 1.2 or a reference outside the document not bundled first, and
155
+ * `OPENAPI_REQUEST` for a call the API refused or did not answer.
108
156
  */
109
157
  readonly code: 'OPENAPI_INVALID' | 'OPENAPI_UNSUPPORTED' | 'OPENAPI_REQUEST';
110
158
  /** The HTTP status the API answered with, when it did. */
@@ -112,8 +160,8 @@ export declare class OpenApiError extends Error {
112
160
  constructor(message: string,
113
161
  /**
114
162
  * `OPENAPI_INVALID` for a malformed document or call, `OPENAPI_UNSUPPORTED` for one these tools
115
- * cannot read, such as Swagger 2.0 or a reference outside the document, and `OPENAPI_REQUEST`
116
- * for a call the API refused or did not answer.
163
+ * cannot read, such as Swagger 1.2 or a reference outside the document not bundled first, and
164
+ * `OPENAPI_REQUEST` for a call the API refused or did not answer.
117
165
  */
118
166
  code: 'OPENAPI_INVALID' | 'OPENAPI_UNSUPPORTED' | 'OPENAPI_REQUEST',
119
167
  /** The HTTP status the API answered with, when it did. */
@@ -124,7 +172,10 @@ export declare class OpenApiError extends Error {
124
172
  * method and path; described by its summary; its path, query, and header parameters, and the fields
125
173
  * of a JSON body, as the tool's parameters. Each declares `api.read`, `api.write`, or
126
174
  * `api.destructive` with the API's name and its own, as its method says, and `network` for the
127
- * API's host when it runs. References within the document are followed; one outside it is refused.
175
+ * API's host when it runs. References within the document are followed; one outside it is refused
176
+ * here, and followed by `loadOpenApiTools()` or `bundleOpenApiDocument()`. A Swagger 2.0 document is
177
+ * read as the OpenAPI 3 document it describes. Each call sends the credentials its operation's
178
+ * security asks for, from `credentials`.
128
179
  *
129
180
  * ```ts
130
181
  * const shop = openApiTools(JSON.parse(await readFile('shop.openapi.json', 'utf8')), {
@@ -135,5 +186,40 @@ export declare class OpenApiError extends Error {
135
186
  * ```
136
187
  */
137
188
  export declare function openApiTools(document: OpenApiDocument | string, options?: OpenApiToolsOptions): OpenApiTools;
138
- /** Fetches an OpenAPI document, as JSON, and reads it into tools, resolving its servers against where it came from. */
139
- export declare function loadOpenApiTools(url: string, options?: OpenApiToolsOptions): Promise<OpenApiTools>;
189
+ /**
190
+ * Fetches an OpenAPI document, as JSON, and reads it into tools, resolving its servers against where
191
+ * it came from, and following its references to other documents on the same origin, or as
192
+ * `references` allows.
193
+ */
194
+ export declare function loadOpenApiTools(url: string, options?: OpenApiToolsOptions & Pick<OpenApiBundleOptions, 'references' | 'maxDocuments' | 'maxBytes'>): Promise<OpenApiTools>;
195
+ /**
196
+ * A Swagger 2.0 document as the OpenAPI 3.0 document it describes: its host, base path, and schemes
197
+ * as a server; its definitions, parameters, responses, and security definitions as components; a
198
+ * body parameter, and form data, as a request body of what it consumes; and each response's schema as
199
+ * content of what it produces. Every reference is moved with what it names.
200
+ */
201
+ export declare function swaggerToOpenApi(swagger: Record<string, unknown>): OpenApiDocument;
202
+ /** Options for `bundleOpenApiDocument()`. */
203
+ export interface OpenApiBundleOptions {
204
+ /** Where the document came from: references outside it are read relative to it. */
205
+ documentUrl: string;
206
+ /**
207
+ * Which documents a reference may name: `same-origin`, the default, only those on the document's
208
+ * own origin; `any`, any HTTP or HTTPS URL; or a function deciding each. A document never makes the
209
+ * tools fetch where it was not allowed to.
210
+ */
211
+ references?: 'same-origin' | 'any' | ((url: string) => boolean);
212
+ /** The most documents read, the first included. Defaults to 50. */
213
+ maxDocuments?: number;
214
+ /** The largest document read, the first included, in bytes. Defaults to 5 MB. */
215
+ maxBytes?: number;
216
+ /** Replaces the global `fetch`. */
217
+ fetch?: typeof globalThis.fetch;
218
+ }
219
+ /**
220
+ * The document with every reference outside it read in its place: each other document fetched, as
221
+ * JSON, relative to the one that names it, its own references followed the same way, and a reference
222
+ * back to one still being read left as a description. `loadOpenApiTools()` does this before reading the
223
+ * document into tools.
224
+ */
225
+ export declare function bundleOpenApiDocument(document: OpenApiDocument, options: OpenApiBundleOptions): Promise<OpenApiDocument>;