Open1

Mastra Agent tool , Googleスプレッドシート連携

knaka Tech-Blogknaka Tech-Blog

概要

  • Mastra.ai Agent tool メモになります。
  • LLMは、Gemini
  • Googleスプレッドシート連携

[ 公開 2025/05/06 ]


構成

  • Mastra 0.6.1
  • LLM: gemini
  • Googleスプレッドシート , Google Drive
  • Google Sheet API
  • node20

関連



書いたコード


  • プロンプト参考
  • 金額の、最小値の指定範囲を 設定する。
getSheetSearchUp を使って、価格 200 JPY以上のリストを。markdown記法の表形式で表示して欲しい。

  • テストデータ: 価格 100~300の金額、タイトル
Title	Price
コーヒー	110
オレンジドリンク	240
レモンドリンク	230
食パン	240
お茶	120
ヨーグルト	140
抹茶コーヒー	280

  • 左 Mastra, 右google Drive
  • 指定金額範囲の、品目行を表示。


  • .env.development
  • SPREADSHEET_ID_2: sheet ID
  • GOOGLE_AUTH_API_KEY: Google 認証API鍵
GOOGLE_GENERATIVE_AI_API_KEY="key"
#Google-Drive
SPREADSHEET_ID_2=""
GOOGLE_AUTH_API_KEY=""

  • Agent
  • src/mastra/agents/firstAgent.ts
import { google } from '@ai-sdk/google';
import { Agent } from '@mastra/core/agent';
import { Memory } from '@mastra/memory';
import { LibSQLStore } from '@mastra/libsql';
import { weatherTool } from '../tools';
import { getNumber } from '../tools/getNumber';
import { getSpreadSheet } from '../tools/getSpreadSheet';
import { getSheetSearchUp } from '../tools/getSheetSearchUp';

const MODEL_NAME = 'gemini-2.0-flash';

export const firstAgent = new Agent({
  name: 'first-Agent',
  instructions: `複数のtool に対応、表示機能、登録機能になります。`,
  model: google(MODEL_NAME),
  tools: { weatherTool, getNumber , getSpreadSheet , getSheetSearchUp },
  memory: new Memory({
    storage: new LibSQLStore({
      url: 'file:../mastra.db', // path is relative to the .mastra/output directory
    }),
    options: {
      lastMessages: 10,
      semanticRecall: false,
      threads: {
        generateTitle: false,
      },
    },
  }),
});


  • tool
  • src/mastra/tools/getSheetSearchUp.ts

import { createTool } from '@mastra/core/tools';
import { z } from 'zod';

// getSheetSearchUp を使って、価格 100 JPY以上のリストを。markdown記法の表形式で表示して欲しい。
export const getSheetSearchUp = createTool({
  id: 'getSheetSearchUp',
  description: "購入品リスト、markdown記法の表形式で表示します。",
  inputSchema: z.object({
    price: z.number().min(1).describe("価格の範囲値の最小値").optional().default(6),
  }),
  execute: async ({ context }) => {
    const sheetId = process.env.SPREADSHEET_ID_2;
    const apiKey = process.env.GOOGLE_AUTH_API_KEY;
    const url = `https://sheets.googleapis.com/v4/spreadsheets/${sheetId}/values/シート1!A1:B100?key=${apiKey}`;
    const response = await fetch(url); 
    if(response.ok === false){
      throw new Error("Error, response <> OK:");
    }
    const json = await response.json();
    let rowMd = "";
    json.values.forEach((row, idx) => {
      const price = Number(row[1]);
      if(idx > 0 && price >= context.price) {
        let target = "| " + row[0] + " | " + row[1] + " | " + "\n";
        rowMd += target;
      }
    });
    let text = `***
| NAME | PRICE |
|:----:|
${rowMd}
***
`;
    //console.log(text);
    return text;
  },
});

src/mastra/index.ts


import { Mastra } from '@mastra/core/mastra';
import { createLogger } from '@mastra/core/logger';
import { LibSQLStore } from '@mastra/libsql';
import { weatherWorkflow } from './workflows';
import { stepWorkflowWork } from './workflows/stepWorkflowWork';

import { weatherAgent } from './agents';
import { firstAgent } from './agents/firstAgent';

//console.log("SPREADSHEET_ID_2=", process.env.SPREADSHEET_ID_2);
//console.log("GOOGLE_AUTH_API_KEY=", process.env.GOOGLE_AUTH_API_KEY);

export const mastra = new Mastra({
  workflows: { stepWorkflowWork },
  agents: { weatherAgent, firstAgent },
  storage: new LibSQLStore({
    // stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db
    url: ":memory:",
  }),
  logger: createLogger({
    name: 'Mastra',
    level: 'info',
  }),
});