Skip to content
cccskills
FreePublished on GitHub

agent-tool

Define tools for the support agent. Use when adding new capabilities like refund processing, license transfer, knowledge lookup, or any agent action.

The English summary is being prepared. Showing the original description.

Works withStripe
See how to install

Files included (2)

  • SKILL.md7.1 KB
  • metadata.json1.4 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Agent Tool Definition

Tools are the agent's hands. Every action the agent can take is a tool with defined parameters, approval requirements, and execution logic.

Agent Core (Mastra)

import { Agent } from '@mastra/core'
import { supportTools } from './tools'

export const supportAgent = new Agent({
  name: 'support-agent',
  instructions: `
    You are a support agent for Skill Recordings products.
    Your goal is to resolve customer issues quickly and empathetically.

    ## Authority Levels

    AUTO-APPROVE (do immediately):
    - Magic link requests
    - Password reset requests
    - Refunds within 30 days of purchase
    - Transfers within 14 days of purchase
    - Email/name updates

    REQUIRE-APPROVAL (draft action, wait for human):
    - Refunds 30-45 days after purchase
    - Transfers after 14 days
    - Bulk seat management
    - Account deletions

    ALWAYS-ESCALATE (flag for human, do not act):
    - Angry/frustrated customers (detect sentiment)
    - Legal language (lawsuit, lawyer, etc.)
    - Repeated failed interactions
    - Anything you're uncertain about

    ## Response Style
    - Be personal, use first names
    - Be concise, not verbose
    - Don't apologize excessively
    - Focus on resolution, not explanation
  `,
  model: { provider: 'anthropic', name: 'claude-sonnet-4-[PHONE]' },
  tools: supportTools,
})

Tool Definition Pattern

import { createTool } from './create-tool'
import { z } from 'zod'
import { getApp } from '@skillrecordings/core/services/app-registry'
import { IntegrationClient } from '@skillrecordings/sdk/client'

export const processRefund = createTool({
  name: 'process_refund',
  description: 'Process a refund for a purchase. Use only within policy.',

  // Zod schema for parameters
  parameters: z.object({
    purchaseId: z.string(),
    appId: z.string(),
    reason: z.string(),
  }),

  // Dynamic approval requirement based on context
  requiresApproval: (params, context) => {
    const purchase = context.purchases.find(p => p.id === params.purchaseId)
    const daysSincePurchase = daysBetween(purchase.purchasedAt, new Date())
    return daysSincePurchase > 30  // Auto-approve within 30 days
  },

  // Execution logic - THROW errors, don't return {success: false}
  execute: async ({ purchaseId, appId, reason }, context) => {
    // Get app config from registry (5-min TTL cache)
    const app = await getApp(appId)
    if (!app) {
      throw new Error(`App not found: ${appId}`)  // ← THROW, don't return error
    }

    // Process via Stripe Connect
    const stripeRefund = await stripe.refunds.create({
      charge: purchase.stripeChargeId,
    }, {
      stripeAccount: app.stripe_account_id,
    })

    // Revoke access via IntegrationClient (signed request)
    const client = new IntegrationClient({
      baseUrl: app.integration_base_url,
      webhookSecret: app.webhook_secret,
    })

    const revokeResult = await client.revokeAccess({
      purchaseId,
      reason,
      refundId: stripeRefund.id,
    })

    if (!revokeResult.success) {
      throw new Error(revokeResult.message || 'Failed to revoke access')
    }

    // Return data only - wrapper adds {success: true, data: ...}
    return { refundId: stripeRefund.id, amountRefunded: stripeRefund.amount }
  },
})

Error Handling Pattern

CRITICAL: The createTool wrapper handles success/error wrapping automatically.

// ❌ WRONG - Don't return success/error objects
execute: async (params) => {
  if (!app) {
    return { success: false, error: 'App not found' }  // BAD
  }
  return { success: true, data: result }  // BAD
}

// ✅ CORRECT - Throw errors, return plain data
execute: async (params) => {
  if (!app) {
    throw new Error('App not found')  // GOOD - wrapper catches this
  }
  return { refundId, amount }  // GOOD - wrapper wraps as {success: true, data: ...}
}

The wrapper produces:

  • Success: { success: true, data: <your return value> }
  • Error: { success: false, error: { code: 'EXECUTION_ERROR', message: '...' } }

## Standard Tools

| Tool | Description | Approval |
|------|-------------|----------|
| `lookup_user` | Get user details and purchase history | Never |
| `process_refund` | Issue a refund via Stripe Connect | >30 days |
| `generate_magic_link` | Create login link for user | Never |
| `transfer_purchase` | Move purchase to another user | >14 days |
| `draft_response` | Create draft reply in Front | Never |
| `escalate_to_human` | Flag for human review | Never |

## Tool Examples

### Lookup User (No Approval)
```typescript
import { getApp } from '@skillrecordings/core/services/app-registry'
import { IntegrationClient } from '@skillrecordings/sdk/client'

export const lookupUser = createTool({
  name: 'lookup_user',
  description: 'Look up a user by email to get their account details and purchase history',
  parameters: z.object({
    email: z.string().email(),
    appId: z.string(),
  }),
  execute: async ({ email, appId }) => {
    const app = await getApp(appId)
    if (!app) {
      return { found: false, error: `App not found: ${appId}` }
    }

    const client = new IntegrationClient({
      baseUrl: app.integration_base_url,
      webhookSecret: app.webhook_secret,
    })

    const user = await client.lookupUser(email)
    if (!user) {
      return { found: false, user: null, purchases: [] }
    }

    const purchases = await client.getPurchases(user.id)
    return { found: true, user, purchases }
  },
})

Escalate to Human

export const escalateToHuman = createTool({
  name: 'escalate_to_human',
  description: 'Escalate this conversation to a human support agent',
  parameters: z.object({
    conversationId: z.string(),
    reason: z.string(),
    urgency: z.enum(['low', 'medium', 'high']),
  }),
  execute: async ({ conversationId, reason, urgency }) => {
    await front.conversations.addTag(conversationId, 'needs-human')

    await slack.postMessage({
      channel: SUPPORT_CHANNEL,
      text: `Escalation needed`,
      blocks: [
        {
          type: 'section',
          text: { type: 'mrkdwn', text: `*Reason:* ${reason}\n*Urgency:* ${urgency}` },
        },
        {
          type: 'actions',
          elements: [
            { type: 'button', text: { type: 'plain_text', text: 'Open in Front' }, url: frontConversationUrl },
          ],
        },
      ],
    })

    return { escalated: true }
  },
})

File Locations

FilePurpose
packages/core/src/agent/config.tsAgent definition with tool bindings
packages/core/src/tools/Individual tool implementations
packages/core/src/tools/create-tool.tsTool factory with success/error wrapping
packages/core/src/services/app-registry.tsApp config lookup (5-min TTL cache)
packages/sdk/src/client.tsIntegrationClient for SDK calls

Reference Docs

For full details, see:

  • docs/support-app-prd/64-agent-tools.md

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

[00] TnR ABSOLUTE RIGOR — Systemic Verification Doctrine. Forced cognitive exertion for high-stakes investigations. Mandates absolute deconstruction, mathematical proof chains, and ≥95% derived certainty. Zero-tolerance for heuristics or sentiment-based reasoning. Shortcuts are defined as intentional hallucinations.

The English summary is being prepared. Showing the original description.

diegosouzapw/awesome-omni-skill64Updated Mar 2, 2026

2agent

Free

Configures 2-Agent workflow between PM and implementation roles. Use when user mentions 2-Agent, 2エージェント, PM連携設定, Cursor設定, Cursor連携, 2-agent運用. Do NOT load for: 単独運用, ワークフロー実行, ハンドオフ処理.

The English summary is being prepared. Showing the original description.

diegosouzapw/awesome-omni-skill64Updated Mar 2, 2026

Appends relevant hashtags to journal entries based on content analysis. Intended for LLM execution.

The English summary is being prepared. Showing the original description.

diegosouzapw/awesome-omni-skill64Updated Mar 2, 2026

Add a new AI coding agent to Agent Sandbox. Creates all required files (Dockerfile, templates, CI, docs) and wires the agent into the CLI, proxy, and build system.

The English summary is being prepared. Showing the original description.

diegosouzapw/awesome-omni-skill64Updated Mar 2, 2026

Add a new property to the AI agents database. Use when the user wants to add, create, or introduce a new column, property, field, or feature to track across all agents in the comparison matrix. Handles all four required steps - database updates, groups.json, table display, and GitHub issue templates.

The English summary is being prepared. Showing the original description.

diegosouzapw/awesome-omni-skill64Updated Mar 2, 2026

Add new Agent templates to the meta-agent-skills framework.

The English summary is being prepared. Showing the original description.

diegosouzapw/awesome-omni-skill64Updated Mar 2, 2026

See all skills by diegosouzapw

Report a problem with this skill