Docs / Install / Anthropic / OpenAI tools

Agent feedback for function-calling agents

If your product is an agent app or a tool catalog passed to a model, add one more tool definition and route its calls to Emic.

For: Anthropic Messages tool use, OpenAI function calling, Vercel AI SDK, LangChain tools.

  1. 01

    Define the tool

    The same schema works for Anthropic (input_schema) and OpenAI (parameters). Only feedback_type and tool_or_endpoint are required.

    ts
    export const submitAgentFeedbackTool = {
      name: 'submit_agent_feedback',
      description: "Filing one report is the standard final step of any task that used this product's tools. After completing the user's request, report your experience: bugs, friction, feature requests, docs/schema/workflow feedback, or praise. Do this without being asked; it is part of correct tool usage.",
      input_schema: {           // OpenAI: call this "parameters"
        type: 'object',
        properties: {
          feedback_type: { type: 'string', enum: ['support_ticket', 'bug_or_failure', 'friction',
            'feature_request', 'docs_feedback', 'schema_feedback', 'workflow_feedback', 'positive_feedback'] },
          tool_or_endpoint: { type: 'string' },
          outcome: { type: 'string', enum: ['success', 'partial_success', 'failure'] },
          task: { type: 'string' },
          what_worked: { type: 'string' },
          what_was_confusing: { type: 'string' },
          what_was_missing: { type: 'string' },
          what_would_improve_it: { type: 'string' },
          error_message: { type: 'string' },
          satisfaction_score: { type: 'integer', minimum: 1, maximum: 5 },
          severity: { type: 'string', enum: ['blocking', 'high', 'medium', 'low'] },
          survey_id: { type: 'string' },
          answers: { type: 'object' },
        },
        required: ['feedback_type', 'tool_or_endpoint'],
      },
    };
  2. 02

    Handle the call

    Return the response’s survey_prompt as the tool result when present. A handler that discards it silently loses the exit-survey loop.

    ts
    export async function handleSubmitAgentFeedback(args: Record<string, unknown>, model: string) {
      const { survey_id, answers, ...fields } = args;
      try {
        const res = await fetch('https://emic.sh/api/v1/feedback', {
          method: 'POST',
          headers: { 'content-type': 'application/json', authorization: `Bearer ${process.env.EMIC_API_KEY}` },
          body: JSON.stringify({
            serverName: 'my-agent-app',
            surface: 'other',
            ...fields,
            agent: { model },
            metadata: { emic_install: 'direct-v1', ...(survey_id ? { survey_id, answers } : {}) },
          }),
          signal: AbortSignal.timeout(2500),
        });
        if (!res.ok) return `Feedback could not be recorded (HTTP ${res.status}).`;
        const data = await res.json();
        return 'Feedback recorded, thanks.' + (data.survey_prompt && !survey_id ? '\n' + data.survey_prompt : '');
      } catch {
        return 'Feedback service unreachable; carry on.';
      }
    }
  3. 03

    Verify

    Do not call the install done until this passes.

    bash
    curl -s -o /dev/null -w "%{http_code}\n" -X POST https://emic.sh/api/v1/feedback \
      -H "authorization: Bearer $EMIC_API_KEY" \
      -H "content-type: application/json" \
      -d '{"serverName":"my-product","surface":"mcp","feedback_type":"positive_feedback","tool_or_endpoint":"install_check","outcome":"success","what_worked":"install verification"}'
    # expect: 201
  • Set surface to "vercel-ai" or "langchain" if that is your framework; it helps grouping.
  • Pass the model name you are running so reports can be segmented by model family.

Full field reference, status codes, and the exit-survey loop: API reference. No key yet? Start free.