sshvarzman-salesforce/claude-skills

sf-service-ai-intake

Live-call AI form-fill experiences for Service Cloud Voice.

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/sshvarzman-salesforce/claude-skills --skill sf-service-ai-intake

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

AI-Assisted Intake on Voice and Digital

Use This Skill When

  • Building CSR-facing intake forms (roadside, claims, complaints, service requests) that fill themselves while the customer talks.
  • Replacing scenario-specific intake LWCs with a configurable, template-driven intake platform.
  • Defining how AI suggestions, agent overrides, and final submissions interact safely on a regulated channel.
  • Planning extension to digital channels (chat, messaging) using the same template + extractor pattern.

Quick Start (Code Patterns)

These four patterns are the load-bearing pieces of an AI-assisted intake. Copy, adapt, ship. For the full data model, prompt construction, and visibility-rule evaluator, see reference.md.

1. One-shot template bundle query (Apex)

Load the template, all questions, picklist values, and visibility rules in a single round-trip. Cacheable so the LWC hydrates fast.

apex
@AuraEnabled(cacheable=true)
public static TemplateBundle getTemplate(Id templateId) {
    if (templateId == null) return null;

    List<Intake_Template__c> templates = [
        SELECT Id, Name, Persona_Description__c, Target_Object_API_Name__c,
               Default_Locale__c, Version__c
        FROM Intake_Template__c
        WHERE Id = :templateId AND Status__c = 'Active'
        LIMIT 1
    ];
    if (templates.isEmpty()) return null;

    List<Intake_Question__c> questions = [
        SELECT Id, DeveloperName__c, Question_Text__c, Help_Text__c,
               Answer_Type__c, Target_Field_API_Name__c, Required__c,
               AI_Extraction_Hint__c, Order__c, Category__c,
               (SELECT Id, Value__c, Label__c, Order__c FROM Intake_Picklist_Values__r),
               (SELECT Id, Source_Question_Developer_Name__c, Operator__c,
                       Value__c, Logic_Group__c FROM Intake_Visibility_Rules__r)
        FROM Intake_Question__c
        WHERE Intake_Template__c = :templateId
        ORDER BY Order__c ASC
    ];

    return new TemplateBundle(templates[0], questions);
}

2. Non-destructive merge (LWC)

The single most important rule: AI suggestions never overwrite a value the agent typed. Agent edits always win.

javascript
_manuallyEdited = new Set();   // dev names the agent has touched

handleAnswerChange(event) {
    const { name, value } = event.detail;
    this._manuallyEdited.add(name);
    this.answers = { ...this.answers, [name]: value };
}

applyAiResults(result) {
    const updatedAnswers = { ...this.answers };
    const newSuggestions = { ...this.suggestions };

    for (const [key, value] of Object.entries(result)) {
        if (this._manuallyEdited.has(key) && updatedAnswers[key]) {
            // Agent already filled this — surface AI guess as a side suggestion only
            if (updatedAnswers[key] !== value) newSuggestions[key] = value;
        } else {
            // Empty or untouched — accept the AI value
            updatedAnswers[key] = value;
            delete newSuggestions[key];
        }
    }

    this.answers = updatedAnswers;
    this.suggestions = newSuggestions;
}

3. Dynamic SObject dispatch on submit (Apex)

Branch on whether the template has a configured target object. Use Schema.getGlobalDescribe() for the dynamic create; check field existence before every put so missing optional fields don't blow up.

apex
public static Id submitIntake(Id templateId, Id voiceCallId, String answersJson) {
    Intake_Template__c tpl = loadTemplate(templateId);
    Map<String, Object> answers = (Map<String, Object>) JSON.deserializeUntyped(answersJson);

    if (String.isNotBlank(tpl.Target_Object_API_Name__c)) {
        return submitToTargetObject(tpl, voiceCallId, answers, answersJson);
    }
    return submitToSubmission(tpl, voiceCallId, answersJson);
}

private static Id submitToTargetObject(Intake_Template__c tpl, Id voiceCallId,
        Map<String, Object> answers, String answersJson) {
    String objApi = tpl.Target_Object_API_Name__c;
    SObject record = Schema.getGlobalDescribe().get(objApi).newSObject();

    if (voiceCallId != null && hasField(objApi, 'VoiceCall__c')) {
        record.put('VoiceCall__c', voiceCallId);
    }

    Map<String, String> devNameToField = getQuestionFieldMap(tpl.Id);
    for (String devName : devNameToField.keySet()) {
        String field = devNameToField.get(devName);
        if (String.isNotBlank(field)
                && hasField(objApi, field)
                && answers.containsKey(devName)) {
            record.put(field, answers.get(devName));
        }
    }

    upsert record;
    return (Id) record.get('Id');
}

private static Boolean hasField(String objApi, String fieldApi) {
    Schema.SObjectType sot = Schema.getGlobalDescribe().get(objApi);
    return sot != null && sot.getDescribe().fields.getMap().containsKey(fieldApi.toLowerCase());
}

4. Visibility rule evaluator (LWC)

Show questions conditionally based on prior answers. Groups are OR-of-ANDs: a question is visible if ANY group passes; a group passes if ALL its rules pass.

javascript
isQuestionVisible(question) {
    const rules = question.visibilityRules || [];
    if (rules.length === 0) return true;

    const groups = new Map();
    for (const rule of rules) {
        const g = rule.logicGroup || 'default';
        if (!groups.has(g)) groups.set(g, []);
        groups.get(g).push(rule);
    }

    for (const groupRules of groups.values()) {
        if (groupRules.every((r) => this.evaluateRule(r))) return true;
    }
    return false;
}

evaluateRule(rule) {
    const sv = String(this.answers[rule.sourceQuestionDeveloperName] ?? '');
    const target = String(rule.value ?? '');
    switch (rule.operator) {
        case 'equals':       return sv === target;
        case 'not_equals':   return sv !== target;
        case 'contains':     return sv.toLowerCase().includes(target.toLowerCase());
        case 'in':           return target.split(';').map((s) => s.trim()).includes(sv);
        case 'is_blank':     return sv === '';
        case 'is_not_blank': return sv !== '';
        default:             return true;
    }
}

Pattern Overview

  1. Intake template as data, not code
  • Model the scenario as records: a template record, ordered question records, picklist values, visibility rules, translations, and an optional target SObject API name.
  • Treat developer-name as the stable contract between the AI extractor and the writeback target field.
  1. Runtime LWC stays generic
  • One runtime renders any active template; it never knows the scenario.
  • The LWC composes the voice-toolkit transcript source and the Models API extractor, both as injected dependencies.
  1. Non-destructive merge is the rule
  • AI suggestions populate empty answers and never overwrite a value the agent typed.
  • Agent edits always win over later AI passes for the same field.

Guardrails

  • The agent always controls submit. AI never auto-submits, even at full coverage.
  • Surface confidence visibly: clearly distinguish agent-confirmed answers (green check) from AI-suggested answers (AI dot) in the UI.
  • Never round-trip free text into a strict picklist field without enum validation against the live field metadata.
  • Honor visibility rules at the prompt layer, not just the UI layer — do not ask the AI to extract fields the agent could not see.
  • Localize question text and validation messages; never localize the developer-name contract.
  • Filter AI responses to the currently visible question set before applying merge — prevents the AI from filling fields hidden by visibility rules.

Deliverables

  • Template design (questions, types, target object, visibility rules, translations).
  • Extraction contract document tying developer-names to prompt schema and writeback fields.
  • Runtime sequence (transcript source → debounce → extractor → merge → UI status → submit).
  • Operational plan: failure routing for extractor errors, audit artifact policy, and prompt-version changelog.

Additional Resources

Related by task

from this repository

More skills

All skills
sshvarzman-salesforce
Community

activating-datacloud

Salesforce Data Cloud Act phase. Use this skill when the user manages activations, activation targets, data actions, or downstream delivery of Data Cloud audiences and data. TRIGGER when: user manages activations, activation targets, data actions, or downstream delivery of Data Cloud audiences and data. DO NOT TRIGGER when: the task is segment creation (use segmenting-datacloud), data retrieval/search work (use retrieving-datacloud), or STDM/session tracing (use observing-agentforce).

installs
1
GitHub stars
0
Updated
Oct 15
sshvarzman-salesforce
Community

agentforce-skills-research

Research Agentforce configuration patterns — topics, actions, instructions, CLTs, knowledge, planner behavior. Searches Salesforce docs, Trailhead, internal repos (git.soma), Slack channels, and Google Docs to find working examples, known issues, and best practices.

installs
1
GitHub stars
0
Updated
Oct 15
sshvarzman-salesforce
Community

harmonizing-datacloud

Salesforce Data Cloud Harmonize phase. Use this skill when the user works with DMOs, mappings, relationships, identity resolution, unified profiles, data graphs, or universal IDs. TRIGGER when: user works with DMOs, mappings, relationships, identity resolution, unified profiles, data graphs, or universal IDs. DO NOT TRIGGER when: the task is only about streams/DLOs (use preparing-datacloud), segments/insights (use segmenting-datacloud), retrieval/search (use retrieving-datacloud), or STDM/sessio

installs
1
GitHub stars
0
Updated
Oct 15
sshvarzman-salesforce
Community

preparing-datacloud

Salesforce Data Cloud Prepare phase. Use this skill when the user creates or manages Data Cloud data streams, DLOs, transforms, or Document AI configurations. TRIGGER when: user creates or manages Data Cloud data streams, DLOs, transforms, or Document AI configurations, or asks about ingestion into Data Cloud. DO NOT TRIGGER when: the task is connection setup only (use connecting-datacloud), DMOs and identity resolution (use harmonizing-datacloud), or query/search work (use retrieving-datacloud)

installs
1
GitHub stars
0
Updated
Oct 15