Polyweave

@polyweave/mistral (1.0.8)

Published 2026-07-11 15:27:37 +00:00 by Dvorak

Installation

@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/
npm install @polyweave/mistral@1.0.8
"@polyweave/mistral": "1.0.8"

About this package

@polyweave/mistral

Mistral AI adapter for Polyweave — Frame-duplex interface to Mistral's API supporting chat (streaming, tools, vision, reasoning), embeddings, FIM code completion, audio transcription (speech-to-text), TTS (text-to-speech), and cost estimation.

Synopsis

import { createMistralAdapter } from '@polyweave/mistral';
import { createTextFrame, createParamFrame } from '@polyweave/core';

const adapter = createMistralAdapter({ apiKey: process.env.MISTRAL_API_KEY });

// Chat with streaming and tools
adapter.sink.write(createParamFrame('model', 'mistral-large-2'));
adapter.sink.write(createParamFrame('stream', true));
adapter.sink.write(createParamFrame('tools', [{ type: 'function', function: { name: 'get_weather', parameters: { type: 'object', properties: { city: { type: 'string' } } } } }]));
adapter.sink.write(createTextFrame("What's the weather in Paris?"));

// Embeddings
adapter.sink.write(createParamFrame('task', 'embeddings'));
adapter.sink.write(createParamFrame('model', 'mistral-embed'));
adapter.sink.write(createTextFrame('Embed this text'));

// FIM (fill-in-middle) code completion
adapter.sink.write(createParamFrame('task', 'fim'));
adapter.sink.write(createParamFrame('prompt', 'function add(a, b) {'));
adapter.sink.write(createParamFrame('suffix', '  return sum;\n}'));
adapter.sink.write(createTextFrame('  let sum = a + b;'));

// Audio transcription (multipart file upload)
const audioBuffer = fs.readFileSync('audio.mp3');
adapter.sink.write({ type: 'AUDIO', content: { data: audioBuffer }, metadata: { mimeType: 'audio/mpeg' } });

// TTS
adapter.sink.write(createParamFrame('task', 'tts'));
adapter.sink.write(createParamFrame('voice', 'mistral'));
adapter.sink.write({ type: 'AUDIO', content: { text: 'Hello, world!' } });

// Cost estimation via COST_CHECK protocol
adapter.sink.write({ type: 'COST_CHECK', content: { maxBudget: 0.01 } });
adapter.sink.write(createTextFrame('Estimate cost only — no API call'));

// Runtime API key injection
adapter.setReady('sk-new-key');  // or via PARAM: adapter.sink.write(createParamFrame('apiKey', 'sk-...'))

Install

npm install @polyweave/mistral

Why

Mistral offers five distinct API surfaces (chat, embeddings, FIM, transcription, TTS) each with different request formats — JSON, multipart/form-data, and SSE streaming. Polyweave harnesses require these unified behind a single Frame-duplex protocol so that budget controllers, topology scanners, and test injectors can operate identically across all capabilities. This adapter translates every capability into the canonical PARAM-accumulation pattern, emits RECEIPT frames with per-second audio pricing and per-token text pricing, and supports progressive receipts during SSE streams for real-time cost tracking.

API

createMistralAdapter(config)

Creates an IFrameDuplex stream adapter. Returns { source, sink, setReady, resetConversation, _conversation, name }.

Parameters:

Name Type Required Default Description
config.apiKey string No process.env.MISTRAL_API_KEY Mistral API key
config.baseURL string No 'https://api.mistral.ai' API base URL
config.timeout number No 60000 Request timeout in milliseconds
config.name string No null Node name for PARAM targeting

Return value:

IFrameDuplex — a duplex stream with .source (readable) and .sink (writable). Additional methods:

  • duplex.setReady(apiKey) — set API key at runtime, flushes buffered frames
  • duplex.resetConversation() — clears accumulated conversation history
  • duplex._conversation() — returns a copy of the current conversation array
  • duplex.name — node name (from config.name, or null)

Frame Protocol

Input frames:

Frame Type Purpose Content fields
PARAM Accumulate configuration { key, value } — persists across requests until overridden
TEXT Chat completion prompt { text }, metadata: role, stream
AUDIO Audio transcription or TTS { data: Buffer | string }, metadata: mimeType
EMBEDDING Embedding request { text } (alternative to TEXT + task=embeddings)
TOOL_RESULT Tool call results { toolCallId, result, content }
COST_CHECK Enable dry-run mode { maxBudget, currency }
ESTIMATED_TEXT Virtual text for cost estimation (no API call) { text }
ESTIMATED_AUDIO Virtual audio for cost estimation { data, mimeType, text }
ESTIMATED_OUTPUT Estimated output metadata { length, tokens, count }
ESTIMATED_IMAGE Virtual image for cost estimation { width, height, quality }
ESTIMATED_VIDEO Virtual video for cost estimation { duration, size }
START Request scope marker (pass-through)
END Request scope marker (pass-through)
TOPOLOGY_SCAN Trigger topology report { path }
TOPOLOGY_REPORT Topology reports (pass-through)
TOPOLOGY_COMPLETE Topology complete (pass-through)
TEST_INJECT Inject test frames { frames: Frame[] }
TEST_SNAPSHOT Request snapshot

Output frames:

Frame Type Emitted when Content
TEXT Chat response chunks or full response { text, embedding }, metadata: role, model, finishReason, streaming, type (embedding/transcription/fim)
TOOL_CALL Tool calls from chat { name, arguments }, metadata: toolCallId, toolCallType
AUDIO TTS audio data { data: Buffer }, content: { mimeType }
RECEIPT Cost receipt after response or during streaming { inputTokens, outputTokens, inputCost, outputCost, totalCost, audioSeconds }, metadata: provider, model, progressive, final
COST Cost check estimate (before API call) { cost, bounds, estimateSource, accuracy, forwardEstimate, inputBounds, maxOutputTokens }
ERROR Error conditions { message, code }, metadata: providerError, statusCode
END End of response metadata: usage, model, error (if error), language (audio)
TOPOLOGY_REPORT Topology scan response { kind, id, connections, state, receives, generates, path }
TEST_SNAPSHOT Test snapshot { kind, id, paused }
META Unknown frame type pass-through { passthrough, frameType, note }

PARAM Keys (persistent configuration)

Chat: model, max_tokens, temperature, top_p, stream, system, tools, tool_choice, response_format, logprobs, top_logprobs, prompt_mode, safe_prompt, random_seed, frequency_penalty, presence_penalty, n, stop, messages

Embeddings: input, encoding_format, output_dimension, output_dtype

FIM: prompt, suffix, min_tokens

Audio: file_id, file_url, language, timestamp_granularities, filename

TTS: voice (default 'mistral'), output_format (default 'mp3')

Task routing: task'embeddings' / 'embed', 'fim' / 'code' / 'completion', 'tts' / 'speech' / 'synthesis'; defaults to chat

Cost/receipt: receipt_mode ('none' | 'final' | 'progressive', default 'final'), receipt_interval (default 50 tokens)

Auth: apiKey (triggers setReady and flushes buffered frames)

Task Routing

Frame types are routed to handlers based on params.task metadata:

task value Frame type Handler API endpoint
(default) TEXT handleChat /v1/chat/completions
embeddings / embed TEXT, EMBEDDING handleEmbeddings /v1/embeddings
fim / code / completion TEXT handleFim /v1/fim/completions
(default) AUDIO handleAudio /v1/audio/transcriptions
tts / speech / synthesis AUDIO handleTTS /v1/audio/speech

Cost Estimation Protocol

  1. Send a COST_CHECK frame to enter dry-run mode
  2. Send content frames (TEXT, AUDIO, ESTIMATED_*)
  3. The adapter estimates cost via @polyweave/costs and emits a COST frame
  4. If maxBudget is set on the COST_CHECK frame and estimated cost exceeds it, emits ERROR with code 'BUDGET_EXCEEDED' followed by END
  5. Cost check mode exits after emitting the estimate

The cost frame content includes: cost (object with inputCost, outputCost, totalCost), bounds (lower/upper confidence bounds), estimateSource (e.g. 'token-count', 'character-heuristic'), accuracy (expected error), forwardEstimate, inputBounds, maxOutputTokens.

Error Conditions

All errors are emitted as ERROR frames (type 'ERROR') through duplex.source.sink, followed by an END frame with metadata: { error: true, errorCode }.

Condition Error Code When
Network error PROVIDER_ERROR HTTP request fails (req.on('error')), stream errors, upload failures
HTTP 401/403 AUTHENTICATION_ERROR / AUTHORIZATION_ERROR Invalid or expired API key
HTTP 429 RATE_LIMIT_EXCEEDED Rate limit exceeded
HTTP 400/422 INVALID_INPUT Malformed request parameters
HTTP 500+ PROVIDER_ERROR Mistral server error
JSON parse failure PROTOCOL_ERROR API response cannot be parsed
No audio input INVALID_INPUT Audio frame has no file buffer, file_id, or file_url
Budget exceeded (COST_CHECK) BUDGET_EXCEEDED Estimated cost > maxBudget in cost check mode
Unrecognized frame type META frame (not an error) Pass-through with passthrough: true note

The mapMistralError function in src/utils/errorMapper.js maps Mistral errors using @polyweave/errors:

  • Uses error.status to determine error code via mapHttpStatusToErrorCode
  • 401/403 → authentication/auth errors
  • 429 → rate limit
  • 400/422 → invalid input
  • All others → provider error (with generic message for 500+)
  • Includes providerError object with original status, message, type in metadata

Audio Transcription Input Modes

The audio handler supports three input formats:

  1. File buffer (Buffer.isBuffer(audioData)): Sends as multipart/form-data with auto-generated boundary. Uses params.filename for the filename field (default 'audio.mp3').
  2. file_id (via params): JSON request with file_id field (previously uploaded file).
  3. file_url (via params): JSON request with file_url field (remote file URL).

Streaming transcription emits incremental TEXT frames, detects and skips the final summary chunk (detected by presence of segments[] after content has accumulated), and handles TTS audio data as AUDIO frames.

Conversation Management

  • Incoming TEXT frames push { role, content } to an internal conversation array
  • TOOL_RESULT frames push { role: 'tool', tool_call_id, content } to conversation
  • Assistant responses from chat are recorded via recordAssistant() which captures role, content, and tool_calls
  • duplex.resetConversation() clears the array; duplex._conversation() returns a snapshot

Re-exports

This package re-exports getModelCost and calculateTokenCost from @polyweave/costs via src/costs.js.

Tests

npm test

Runs node --test test/mistral.test.js test/rigor.test.js. Covers:

  • createMistralAdapter construction with default config
  • Adapter topology report structure — verifies receives and generates frame types
  • PARAM frame accumulation (model, temperature, etc.)
  • FIM, embedding, and audio default configurations
  • setReady flushes buffered frames
  • resetConversation clears conversation
  • COST_CHECK protocol: entry, estimation frames, budget exceeded, exit

Requirements

  • Node.js >= 22.0.0
  • ESM only ("type": "module")
  • Peer dependencies: @polyweave/core, @polyweave/errors, @polyweave/costs

Dependencies

Development Dependencies

ID Version
@rigor/core *

Peer Dependencies

ID Version
@polyweave/core *
@polyweave/costs *
@polyweave/errors *

Keywords

polyweave mistral ai adapter
Details
npm
2026-07-11 15:27:37 +00:00
5
John Dvorak
SEE LICENSE IN LICENSE
latest
16 KiB
Assets (1)
Versions (5) View all
1.0.8 2026-07-11
1.0.5 2026-07-10
1.0.4 2026-07-10
1.0.3 2026-07-10
1.0.2 2026-07-10