Mastra — Example Configuration

JavaScript / TypeScript only — Mastra is a TS agent framework built on the Vercel AI SDK. Weflayr instruments it via a transparent JS Proxy on the Agent instance; no Mastra internals are modified.

Setup

const { weflayr_setup, weflayr_instrument } = require('weflayr');
const { Agent } = require('@mastra/core');
const { openai } = require('@ai-sdk/openai');

weflayr_setup({
  intake_url:    process.env.WEFLAYR_INTAKE_URL,
  client_id:     process.env.WEFLAYR_CLIENT_ID,
  client_secret: process.env.WEFLAYR_CLIENT_SECRET,
  methods: [{ call: 'generate' }],
});

const agent = weflayr_instrument(
  new Agent({
    name:         'my-agent',
    model:        openai('gpt-4o-mini'),
    instructions: 'You are a helpful assistant.',
  })
);

Tagging calls

Pass __weflayr_tags in the options object (second argument to generate()). The key is stripped before Mastra receives the call.

await agent.generate(
  [{ role: 'user', content: 'Hello' }],
  { __weflayr_tags: { feature: 'chat', customer_id: '42', env: 'prod' } },
);

Content privacy

Mastra’s result contains the full request body (system prompt, user messages) and raw API response. Strip content before it reaches the intake:

const { weflayr_setup, weflayr_instrument } = require('weflayr');
const { Agent } = require('@mastra/core');
const { openai } = require('@ai-sdk/openai');

weflayr_setup({
  intake_url:    process.env.WEFLAYR_INTAKE_URL,
  client_id:     process.env.WEFLAYR_CLIENT_ID,
  client_secret: process.env.WEFLAYR_CLIENT_SECRET,
  methods: [{ call: 'generate' }],
  ignore_fields: (data) => {
    delete data.text;
    delete data.request;
    delete data.steps;
    if (data.response) {
      delete data.response.body;
      delete data.response.messages;
    }
    return data;
  },
});

const agent = weflayr_instrument(
  new Agent({
    name:         'my-agent',
    model:        openai('gpt-4o-mini'),
    instructions: 'You are a helpful assistant.',
  })
);

After applying this policy, events retain usage, finishReason, modelId, and response headers — no message content.

Streaming with agent.stream()

Mastra’s StreamTextResult is not directly async-iterable — its text chunks live under a textStream property. Use streamPath: "textStream" to point weflayr at the right iterable.

Usage and model are not in the text chunks themselves; they resolve as promises on the full result after the stream drains. The streamMiddleware factory receives fullResult (the full StreamTextResult) so you can await them in finalize().

const { weflayr_setup, weflayr_instrument } = require('weflayr');
const { Agent } = require('@mastra/core');
const { openai } = require('@ai-sdk/openai');

weflayr_setup({
  intake_url:    process.env.WEFLAYR_INTAKE_URL,
  client_id:     process.env.WEFLAYR_CLIENT_ID,
  client_secret: process.env.WEFLAYR_CLIENT_SECRET,
  methods: [
    { call: 'generate' },
    {
      call: 'stream',
      streamPath: 'textStream',
      streamMiddleware: (fullResult) => ({
        onChunk: () => false,
        async finalize() {
          const rawUsage    = await fullResult.usage;
          const rawResponse = await fullResult.response;
          const response    = rawResponse?.status?.value ?? rawResponse;
          return {
            usage: rawUsage,
            model: response?.modelId ?? null,
          };
        },
      }),
    },
  ],
  ignore_fields: (data) => {
    delete data.text;
    delete data.request;
    delete data.steps;
    if (data.response) {
      delete data.response.body;
      delete data.response.messages;
    }
    return data;
  },
});

const agent = weflayr_instrument(
  new Agent({
    name:         'my-agent',
    model:        openai('gpt-4o-mini'),
    instructions: 'You are a helpful assistant.',
  })
);

const streamResult = await agent.stream(
  [{ role: 'user', content: 'Hello' }],
  { __weflayr_tags: { feature: 'chat', customer_id: '42' } },
);

let text = '';
for await (const chunk of streamResult.textStream) {
  text += chunk;
}

The after event for a stream call contains:

Field Value
model e.g. "gpt-4o-mini-2024-07-18" — from fullResult.response.modelId
usage { promptTokens, completionTokens, totalTokens } — from fullResult.usage
response Last text fragment from textStream (e.g. ".") — strip with ignore_fields if unwanted

Why rawResponse?.status?.value ?? rawResponse Mastra wraps SDK results in internal DelayedPromise objects. Calling await on one returns the wrapper ({ status: { type: "resolved", value: {...} } }) rather than the resolved value. The ?.status?.value ?? rawResponse pattern unwraps it safely while staying compatible if the underlying SDK returns a real Promise.

Configuration notes

Setting Value Reason
methods[generate] generate Top-level method on the Agent instance
methods[stream].streamPath textStream StreamTextResult is not directly iterable; text chunks are on textStream
streamMiddleware factory arg fullResult Weflayr passes the full SDK result so usage and response.modelId are accessible after drain
requestArgs Options object (last arg) The messages array is the first arg and is ignored; the model is not in args

What Weflayr captures

Field generate stream
elapsed_ms
tags
response Full GenerateTextResult Last text chunk from textStream
model — (use middleware) From fullResult.response.modelId via streamMiddleware
usage — (use middleware) From fullResult.usage via streamMiddleware