@salesforce/afv-skills 1.6.9 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/developing-agentforce/README.md +112 -0
- package/skills/{agentforce-development → developing-agentforce}/SKILL.md +109 -16
- package/skills/{agentforce-development → developing-agentforce}/assets/agents/README.md +2 -2
- package/skills/developing-agentforce/assets/agents/order-service.agent +272 -0
- package/skills/developing-agentforce/assets/agents/verification-gate.agent +280 -0
- package/skills/{agentforce-development → developing-agentforce}/assets/bundle-meta.xml +1 -1
- package/skills/{agentforce-development → developing-agentforce}/references/actions-reference.md +20 -0
- package/skills/{agentforce-development → developing-agentforce}/references/agent-design-and-spec-creation.md +1 -1
- package/skills/{agentforce-development → developing-agentforce}/references/agent-metadata-and-lifecycle.md +3 -3
- package/skills/{agentforce-development → developing-agentforce}/references/agent-script-core-language.md +40 -3
- package/skills/{agentforce-development → developing-agentforce}/references/agent-user-setup.md +60 -57
- package/skills/{agentforce-development → developing-agentforce}/references/agent-validation-and-debugging.md +22 -20
- package/skills/developing-agentforce/references/architecture-patterns.md +158 -0
- package/skills/developing-agentforce/references/complex-data-types.md +57 -0
- package/skills/developing-agentforce/references/deploy-reference.md +134 -0
- package/skills/developing-agentforce/references/discover-reference.md +102 -0
- package/skills/developing-agentforce/references/examples.md +350 -0
- package/skills/developing-agentforce/references/feature-validity.md +43 -0
- package/skills/developing-agentforce/references/instruction-resolution.md +545 -0
- package/skills/{agentforce-development → developing-agentforce}/references/known-issues.md +18 -18
- package/skills/{agentforce-development → developing-agentforce}/references/production-gotchas.md +24 -3
- package/skills/developing-agentforce/references/safety-review-reference.md +145 -0
- package/skills/{agentforce-development → developing-agentforce}/references/salesforce-cli-for-agents.md +9 -7
- package/skills/developing-agentforce/references/scaffold-reference.md +153 -0
- package/skills/developing-agentforce/references/scoring-rubric.md +24 -0
- package/skills/{agentforce-development → developing-agentforce}/references/version-history.md +2 -2
- package/skills/observing-agentforce/SKILL.md +368 -0
- package/skills/observing-agentforce/apex/AgentforceOptimizeService.cls +1262 -0
- package/skills/observing-agentforce/apex/AgentforceOptimizeService.cls-meta.xml +5 -0
- package/skills/observing-agentforce/references/improve-reference.md +359 -0
- package/skills/observing-agentforce/references/issue-classification.md +220 -0
- package/skills/observing-agentforce/references/reproduce-reference.md +131 -0
- package/skills/observing-agentforce/references/stdm-queries.md +381 -0
- package/skills/observing-agentforce/references/stdm-schema.md +189 -0
- package/skills/testing-agentforce/SKILL.md +335 -0
- package/skills/testing-agentforce/assets/basic-test-spec.yaml +59 -0
- package/skills/testing-agentforce/assets/guardrail-test-spec.yaml +101 -0
- package/skills/testing-agentforce/assets/standard-test-spec.yaml +123 -0
- package/skills/testing-agentforce/references/action-execution.md +241 -0
- package/skills/testing-agentforce/references/batch-testing.md +274 -0
- package/skills/testing-agentforce/references/preview-testing.md +353 -0
- package/skills/testing-agentforce/references/test-report-format.md +160 -0
- package/skills/testing-agentforce/references/troubleshooting.md +73 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/README-legacy.md +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/agent-spec-template.md +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/agents/hello-world.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/agents/multi-topic.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/agents/production-faq.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/agents/production-faq.bundle-meta.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/agents/simple-qa.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/apex/models-api-queueable.cls +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/components/apex-action.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/components/error-handling.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/components/escalation-setup.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/components/flow-action.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/components/n-ary-conditions.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/components/topic-with-actions.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/deterministic-routing.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/escalation-pattern.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/flow-action-lookup.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/hub-and-spoke.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/invocable-apex-template.cls +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/local-info-agent-annotated.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/metadata/basic-prompt-template.promptTemplate-meta.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/metadata/genai-function-apex.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/metadata/genai-function-flow.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/metadata/genai-plugin.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/metadata/http-callout-flow.flow-meta.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/metadata/record-grounded-prompt.promptTemplate-meta.xml +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/minimal-starter.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/README.md +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/action-callbacks.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/advanced-input-bindings.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/bidirectional-routing.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/critical-input-collection.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/delegation-routing.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/lifecycle-events.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/llm-controlled-actions.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/multi-step-workflow.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/open-gate-routing.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/procedural-instructions.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/prompt-template-action.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/patterns/system-instruction-overrides.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/prompt-rag-search.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/template-multi-topic.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/template-single-topic.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/assets/verification-gate.agent +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/references/action-prompt-templates.md +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/references/agent-access-guide.md +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/references/agent-topic-map-diagrams.md +0 -0
- /package/skills/{agentforce-development → developing-agentforce}/references/minimal-examples.md +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Phase 2: Reproduce -- Live Preview (Full Reference)
|
|
2
|
+
|
|
3
|
+
Use `sf agent preview` to simulate conversations in an isolated session (no production data affected).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Build Test Scenarios from Phase 1 Findings
|
|
8
|
+
|
|
9
|
+
Before opening a preview session, define one test scenario per confirmed issue:
|
|
10
|
+
|
|
11
|
+
| Issue type (Phase 1) | Test message to send | Expected behavior | Failure indicator |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| Dead topic -- never entered | Utterance that *should* route to that topic | `topic` in response = `<dead_topic>` | Topic stays `entry` |
|
|
14
|
+
| Action not called | Ask directly for the action's task | Action fires in the response | Conversational reply with no action invoked |
|
|
15
|
+
| Handoff topic -- no post-collection routing | Enter the handoff topic, then send a follow-up | Session continues in specialized topic | Falls back to `entry` after 1 turn |
|
|
16
|
+
| LOW adherence | Exact utterance from the flagged `TRUST_GUARDRAILS_STEP` | Response follows topic instruction | Generic/off-instruction answer |
|
|
17
|
+
| Knowledge miss | Question requiring a specific knowledge article | Agent cites correct information | Hallucinated or generic answer |
|
|
18
|
+
| Topic misroute | Utterance that belongs to topic A | `topic` = A in response | `topic` = B or `entry` |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Run a Preview Session
|
|
23
|
+
|
|
24
|
+
Use `--authoring-bundle` to compile from the local `.agent` file and generate local trace files:
|
|
25
|
+
|
|
26
|
+
| Flag | Compiles from | Local traces? | Use when |
|
|
27
|
+
|------|---------------|---------------|----------|
|
|
28
|
+
| `--authoring-bundle <BundleName>` | Local `.agent` file | YES | Development iteration (recommended) |
|
|
29
|
+
| `--api-name <name>` | Last published version | NO | Testing activated agent |
|
|
30
|
+
|
|
31
|
+
> **Note:** `--authoring-bundle` must appear on all three subcommands (`start`, `send`, `end`).
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Start a preview session (--authoring-bundle enables local traces)
|
|
35
|
+
sf agent preview start --json \
|
|
36
|
+
--authoring-bundle <AgentApiName> \
|
|
37
|
+
-o <org> | tee /tmp/preview_start.json
|
|
38
|
+
|
|
39
|
+
# Extract the session ID
|
|
40
|
+
SESSION_ID=$(python3 -c "import json,sys; print(json.load(open('/tmp/preview_start.json'))['result']['sessionId'])")
|
|
41
|
+
echo "Session ID: $SESSION_ID"
|
|
42
|
+
|
|
43
|
+
# Send the test utterance (flag is --utterance, not --message)
|
|
44
|
+
sf agent preview send --json \
|
|
45
|
+
--session-id "$SESSION_ID" \
|
|
46
|
+
--utterance "your test utterance here" \
|
|
47
|
+
--authoring-bundle <AgentApiName> \
|
|
48
|
+
-o <org> | tee /tmp/preview_response.json
|
|
49
|
+
|
|
50
|
+
# Extract the agent's response text
|
|
51
|
+
# The message type is "Inform" in current API versions -- print all messages regardless of type
|
|
52
|
+
python3 -c "
|
|
53
|
+
import json
|
|
54
|
+
data = json.load(open('/tmp/preview_response.json'))
|
|
55
|
+
result = data.get('result', data)
|
|
56
|
+
# Response field varies by API version -- try common shapes
|
|
57
|
+
for key in ['messages', 'message', 'response']:
|
|
58
|
+
if key in result:
|
|
59
|
+
msgs = result[key] if isinstance(result[key], list) else [result[key]]
|
|
60
|
+
for m in msgs:
|
|
61
|
+
if isinstance(m, dict):
|
|
62
|
+
msg_type = m.get('type', '?')
|
|
63
|
+
msg_text = m.get('message', m.get('text', m))
|
|
64
|
+
print(f'Agent [{msg_type}]: {msg_text}')
|
|
65
|
+
break
|
|
66
|
+
else:
|
|
67
|
+
print(json.dumps(result, indent=2)) # fallback: print full result
|
|
68
|
+
"
|
|
69
|
+
|
|
70
|
+
# End the session when done (--authoring-bundle required on end too)
|
|
71
|
+
sf agent preview end --json \
|
|
72
|
+
--session-id "$SESSION_ID" \
|
|
73
|
+
--authoring-bundle <AgentApiName> \
|
|
74
|
+
-o <org>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Trace file location:**
|
|
78
|
+
```
|
|
79
|
+
.sfdx/agents/{AgentApiName}/sessions/{sessionId}/traces/{planId}.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For multi-turn scenarios (e.g. handoff routing), repeat the `send` step for each follow-up utterance before ending the session.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Local Trace Diagnosis
|
|
87
|
+
|
|
88
|
+
For each Phase 1 issue type, diagnose from the local trace:
|
|
89
|
+
|
|
90
|
+
| Phase 1 Issue | Local Trace Command |
|
|
91
|
+
|---|---|
|
|
92
|
+
| Topic misroute | `jq -r '.topic' "$TRACE"` + `jq -r '.plan[] \| select(.type=="NodeEntryStateStep") \| .data.agent_name' "$TRACE"` |
|
|
93
|
+
| Action not called | `jq -r '.plan[] \| select(.type=="EnabledToolsStep") \| .data.enabled_tools[]' "$TRACE"` |
|
|
94
|
+
| LOW adherence | `jq -r '.plan[] \| select(.type=="ReasoningStep") \| {category, reason}' "$TRACE"` |
|
|
95
|
+
| Variable capture fail | `jq -r '.plan[] \| select(.type=="VariableUpdateStep") \| .data.variable_updates[] \| "\(.variable_name): \(.variable_past_value) -> \(.variable_new_value) (\(.variable_change_reason))"' "$TRACE"` |
|
|
96
|
+
| Vague/wrong instructions | `jq -r '.plan[] \| select(.type=="LLMStep") \| .data.messages_sent[0].content' "$TRACE"` |
|
|
97
|
+
|
|
98
|
+
**UNGROUNDED retry detection:** When grounding returns UNGROUNDED, you'll see the retry pattern: UNGROUNDED -> error injection -> second LLMStep -> second ReasoningStep. Count `ReasoningStep` entries (>1 = retry happened):
|
|
99
|
+
```bash
|
|
100
|
+
jq '[.plan[] | select(.type == "ReasoningStep")] | length' "$TRACE"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Classify Each Scenario
|
|
106
|
+
|
|
107
|
+
Run each test scenario **3 times** (start a new session each run) and classify:
|
|
108
|
+
|
|
109
|
+
| Verdict | Criteria |
|
|
110
|
+
|---|---|
|
|
111
|
+
| `[CONFIRMED]` | Same failure in 3/3 runs |
|
|
112
|
+
| `[INTERMITTENT]` | Failure in 1-2 of 3 runs |
|
|
113
|
+
| `[NOT REPRODUCED]` | Passes in 3/3 runs -- re-examine Phase 1 evidence |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Record Results
|
|
118
|
+
|
|
119
|
+
For each scenario, record before proceeding to Phase 3:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Scenario: <issue type from Phase 1>
|
|
123
|
+
Test message: "<exact utterance sent>"
|
|
124
|
+
Expected: <topic name / action name / response behavior>
|
|
125
|
+
Actual: <observed topic / action / verbatim response>
|
|
126
|
+
Verdict: [CONFIRMED] / [INTERMITTENT] / [NOT REPRODUCED]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Only `[CONFIRMED]` and `[INTERMITTENT]` issues proceed to Phase 3.
|
|
130
|
+
|
|
131
|
+
For `[NOT REPRODUCED]` issues: re-examine the Phase 1 STDM evidence. The session data may be stale (issue was already fixed), the utterance may not match the original user input closely enough, or the issue may be environment-dependent. Report these to the user as "not reproducible" and move on -- do not attempt fixes for issues that cannot be confirmed.
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# STDM Query Reference
|
|
2
|
+
|
|
3
|
+
Detailed procedures for querying Session Trace Data Model (STDM) via the `AgentforceOptimizeService` Apex helper class.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Deploy Helper Class (Once Per Org)
|
|
8
|
+
|
|
9
|
+
`AgentforceOptimizeService` is a bundled Apex class that queries STDM DMOs and returns clean JSON. Deploy it once; subsequent runs reuse the deployed class.
|
|
10
|
+
|
|
11
|
+
Methods:
|
|
12
|
+
- `findSessions(dataSpaceName, startIso, endIso, maxRows, agentName)` -> `List<SessionSummary>`
|
|
13
|
+
- `getConversationDetails(dataSpaceName, sessionId)` -> `ConversationData`
|
|
14
|
+
- `getMultipleConversationDetails(dataSpaceName, sessionIds)` -> `List<ConversationData>`
|
|
15
|
+
- `getLlmStepDetails(dataSpaceName, stepIds)` -> `List<LlmStepDetail>`
|
|
16
|
+
- `getMomentInsights(dataSpaceName, sessionIds)` -> `List<SessionInsights>` (moments, turn counts, retriever metrics)
|
|
17
|
+
- `getAggregatedMetrics(dataSpaceName, startIso, endIso, maxRows, agentName)` -> `AggregatedMetrics` (session rates, top intents, RAG quality)
|
|
18
|
+
- `runObservabilityQuery(List<ObservabilityInput>)` -> `List<ObservabilityOutput>` (@InvocableMethod -- RAG observability queries for Flow/Agentforce actions)
|
|
19
|
+
|
|
20
|
+
**Step 1 -- copy the class into the project:**
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Ensure the classes directory exists
|
|
24
|
+
mkdir -p <project-root>/force-app/main/default/classes
|
|
25
|
+
|
|
26
|
+
# Copy from the installed skill location
|
|
27
|
+
cp skills/observing-agentforce/apex/AgentforceOptimizeService.cls \
|
|
28
|
+
<project-root>/force-app/main/default/classes/
|
|
29
|
+
cp skills/observing-agentforce/apex/AgentforceOptimizeService.cls-meta.xml \
|
|
30
|
+
<project-root>/force-app/main/default/classes/
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If the skill is installed globally via the installer, use the installed path:
|
|
34
|
+
```bash
|
|
35
|
+
cp ~/.claude/skills/observing-agentforce/apex/AgentforceOptimizeService.cls \
|
|
36
|
+
<project-root>/force-app/main/default/classes/
|
|
37
|
+
cp ~/.claude/skills/observing-agentforce/apex/AgentforceOptimizeService.cls-meta.xml \
|
|
38
|
+
<project-root>/force-app/main/default/classes/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Step 2 -- ensure `sfdx-project.json` exists** (if absent, create a minimal one):
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"packageDirectories": [{ "path": "force-app", "default": true }],
|
|
46
|
+
"sourceApiVersion": "63.0"
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Step 3 -- deploy to the org:**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
sf project deploy start --json \
|
|
54
|
+
--metadata ApexClass:AgentforceOptimizeService \
|
|
55
|
+
-o <org>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Confirm the deploy succeeds before proceeding. If it fails with a compile error, check that the org has Data Cloud enabled (the `ConnectApi.CdpQuery` namespace requires Data Cloud).
|
|
59
|
+
|
|
60
|
+
**Skip this step if `AgentforceOptimizeService` is already deployed** -- check with:
|
|
61
|
+
```bash
|
|
62
|
+
sf data query --json \
|
|
63
|
+
--query "SELECT Id, Name FROM ApexClass WHERE Name = 'AgentforceOptimizeService'" \
|
|
64
|
+
-o <org>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Find Sessions
|
|
70
|
+
|
|
71
|
+
If the user provided session IDs, skip to conversation details. Otherwise, write `/tmp/stdm_find.apex` and run it (substitute actual ISO 8601 UTC timestamps, DATA_SPACE, and AGENT_API_NAME):
|
|
72
|
+
|
|
73
|
+
```apex
|
|
74
|
+
String result = AgentforceOptimizeService.findSessions(
|
|
75
|
+
'DATA_SPACE',
|
|
76
|
+
'START_ISO',
|
|
77
|
+
'END_ISO',
|
|
78
|
+
20,
|
|
79
|
+
'AGENT_MASTER_LABEL'
|
|
80
|
+
);
|
|
81
|
+
System.debug('STDM_RESULT:' + result);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
sf apex run --json --file /tmp/stdm_find.apex -o <org>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Parse: search for `DEBUG|STDM_RESULT:` (not `STDM_RESULT:` -- the first occurrence of that string is in the source echo, not the debug output) and extract the JSON that follows on that line:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
python3 -c "
|
|
92
|
+
import json, sys
|
|
93
|
+
logs = json.load(sys.stdin)['result']['logs']
|
|
94
|
+
idx = logs.find('DEBUG|STDM_RESULT:')
|
|
95
|
+
print(logs[idx + len('DEBUG|STDM_RESULT:'):].split('\n')[0].strip())
|
|
96
|
+
" < /tmp/apex_result.json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The result is a JSON array of `SessionSummary` objects:
|
|
100
|
+
```json
|
|
101
|
+
[
|
|
102
|
+
{
|
|
103
|
+
"session_id": "...", "start_time": "...", "end_time": "...",
|
|
104
|
+
"channel": "...", "duration_ms": 12345,
|
|
105
|
+
"end_type": "USER_ENDED"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `end_time` and `duration_ms` may be `null` when the session has no recorded end event -- this is a normal STDM data quality gap, not an error.
|
|
111
|
+
- `end_type` values: `USER_ENDED`, `AGENT_ENDED`, or `null` (in-progress or not recorded). A `null` `end_type` may indicate an abandoned session.
|
|
112
|
+
|
|
113
|
+
**Session quality filter:** `findSessions` automatically filters to sessions with actual conversation turns by querying `AiAgentInteraction` first. Sessions from `sf agent preview`, `sf agent test`, and Agent Builder that created `AiAgentSession` records but no `AiAgentInteraction` (TURN) records are excluded. If `findSessions` returns an empty list, there are no sessions with actionable data — go directly to Phase 1-ALT (local traces).
|
|
114
|
+
|
|
115
|
+
**How agent filtering works** -- `findSessions` tries two strategies in order:
|
|
116
|
+
|
|
117
|
+
1. **Direct** (preferred): `ssot__AiAgentApiName__c = agentApiName` on `ssot__AiAgentSessionParticipant__dlm` -- no SOQL needed, uses a dedicated DMO field. Resolves in a single Data Cloud query.
|
|
118
|
+
2. **Planner fallback**: If strategy 1 returns no rows, SOQL: `SELECT Id FROM GenAiPlannerDefinition WHERE MasterLabel = :agentApiName` -> `ssot__ParticipantId__c IN (...)`. Both 15-char and 18-char ID formats are included (the DMO stores them inconsistently). If both strategies return empty, the query falls back to all sessions in the date range.
|
|
119
|
+
|
|
120
|
+
**If the debug log shows `Agent not found: <name>`**, no `GenAiPlannerDefinition` matched -- verify the agent name with:
|
|
121
|
+
```bash
|
|
122
|
+
sf data query --json --query "SELECT Id, MasterLabel, DeveloperName FROM GenAiPlannerDefinition" -o <org>
|
|
123
|
+
```
|
|
124
|
+
Use the exact `MasterLabel` value (not `DeveloperName`). `MasterLabel` matches the agent's display name; `DeveloperName` has a version suffix (e.g. `TeslaSupportAgent_v1`).
|
|
125
|
+
|
|
126
|
+
**If the debug log shows a warning about no sessions for the agent**, both strategies returned empty -- the agent may have no sessions in this date range, or Data Cloud ingestion may be delayed. The query falls back to all sessions in the date range.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Get Conversation Details
|
|
131
|
+
|
|
132
|
+
For up to 5 sessions (most recent first), write `/tmp/stdm_details.apex` and run it (substitute session IDs and DATA_SPACE):
|
|
133
|
+
|
|
134
|
+
```apex
|
|
135
|
+
String result = AgentforceOptimizeService.getMultipleConversationDetails(
|
|
136
|
+
'DATA_SPACE',
|
|
137
|
+
new List<String>{ 'SESSION_ID_1', 'SESSION_ID_2' }
|
|
138
|
+
);
|
|
139
|
+
System.debug('STDM_RESULT:' + result);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
sf apex run --json --file /tmp/stdm_details.apex -o <org>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Parse using the same `DEBUG|STDM_RESULT:` pattern. Each element is a `ConversationData` object:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"session_id": "...",
|
|
151
|
+
"start_time": "...", "end_time": "...", "channel": "...",
|
|
152
|
+
"duration_ms": 45000,
|
|
153
|
+
"end_type": "USER_ENDED",
|
|
154
|
+
"session_variables": "{...}",
|
|
155
|
+
"turn_count": 3,
|
|
156
|
+
"action_error_count": 1,
|
|
157
|
+
"turns": [
|
|
158
|
+
{
|
|
159
|
+
"interaction_id": "...",
|
|
160
|
+
"topic": "CheckOrderStatus",
|
|
161
|
+
"start_time": "...", "end_time": "...", "duration_ms": 8000,
|
|
162
|
+
"telemetry_trace_id": "...",
|
|
163
|
+
"messages": [
|
|
164
|
+
{ "message_type": "Input", "text": "Where is my order?", "sent_at": "..." },
|
|
165
|
+
{ "message_type": "Output", "text": "I found your order...", "sent_at": "..." }
|
|
166
|
+
],
|
|
167
|
+
"steps": [
|
|
168
|
+
{ "step_type": "TOPIC_STEP", "name": "CheckOrderStatus" },
|
|
169
|
+
{ "step_type": "LLM_STEP", "name": "...", "duration_ms": 3200,
|
|
170
|
+
"generation_id": "abc123", "gateway_request_id": "def456" },
|
|
171
|
+
{ "step_type": "ACTION_STEP", "name": "GetOrderDetails",
|
|
172
|
+
"input": "{...}", "output": "{...}", "error": null,
|
|
173
|
+
"pre_vars": "{...}", "post_vars": "{...}", "duration_ms": 1500 }
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Key fields:
|
|
181
|
+
- `end_type` -- how the session ended (`USER_ENDED`, `AGENT_ENDED`, or null)
|
|
182
|
+
- `session_variables` -- final variable snapshot for the session (null when absent)
|
|
183
|
+
- `telemetry_trace_id` -- distributed tracing ID for this turn (null when absent)
|
|
184
|
+
- `generation_id` / `gateway_request_id` on `LLM_STEP` -- pass these step IDs to `getLlmStepDetails()` to retrieve the actual LLM prompt and response (useful for diagnosing LOW instruction adherence)
|
|
185
|
+
|
|
186
|
+
Treat any `null` field as absent/unknown. The `"NOT_SET"` sentinel is stripped by the service class before returning.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Get LLM Prompt/Response (Optional, for LOW Adherence)
|
|
191
|
+
|
|
192
|
+
When a session shows `TRUST_GUARDRAILS_STEP` with `'value': 'LOW'`, use `getLlmStepDetails()` to retrieve the actual LLM prompt and response for the associated `LLM_STEP` records. Pass the `step_id` values from steps where `step_type == "LLM_STEP"` and `generation_id != null`.
|
|
193
|
+
|
|
194
|
+
```apex
|
|
195
|
+
String result = AgentforceOptimizeService.getLlmStepDetails(
|
|
196
|
+
'DATA_SPACE',
|
|
197
|
+
new List<String>{ 'STEP_ID_1', 'STEP_ID_2' }
|
|
198
|
+
);
|
|
199
|
+
System.debug('STDM_RESULT:' + result);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
sf apex run --json --file /tmp/stdm_llm.apex -o <org>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Returns a JSON array of `LlmStepDetail` objects:
|
|
207
|
+
```json
|
|
208
|
+
[
|
|
209
|
+
{
|
|
210
|
+
"step_id": "...",
|
|
211
|
+
"interaction_id": "...",
|
|
212
|
+
"step_name": "...",
|
|
213
|
+
"prompt": "System: You are a Tesla support agent...\nUser: I want to schedule a test drive",
|
|
214
|
+
"llm_response": "I'd be happy to help you schedule a test drive...",
|
|
215
|
+
"generation_id": "...",
|
|
216
|
+
"gateway_request_id": "..."
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- `prompt` -- full prompt from `GenAIGatewayRequest__dlm.prompt__c` (null if Einstein Audit DMO not enabled)
|
|
222
|
+
- `llm_response` -- model response from `GenAIGeneration__dlm.responseText__c` (null if not available)
|
|
223
|
+
|
|
224
|
+
Use these to confirm whether the agent's instructions were included in the prompt and whether the response deviated from them.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Get Aggregated Metrics (Recommended First Step)
|
|
229
|
+
|
|
230
|
+
Before drilling into individual sessions, get a high-level health dashboard with `getAggregatedMetrics()`. This gives session rates, top intents, and RAG quality averages across the date range.
|
|
231
|
+
|
|
232
|
+
```apex
|
|
233
|
+
String result = AgentforceOptimizeService.getAggregatedMetrics(
|
|
234
|
+
'DATA_SPACE',
|
|
235
|
+
'START_ISO',
|
|
236
|
+
'END_ISO',
|
|
237
|
+
50,
|
|
238
|
+
'AGENT_MASTER_LABEL'
|
|
239
|
+
);
|
|
240
|
+
System.debug('STDM_RESULT:' + result);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Returns an `AggregatedMetrics` object:
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"total_sessions": 36,
|
|
247
|
+
"total_moments": 32,
|
|
248
|
+
"total_turns": 101,
|
|
249
|
+
"avg_quality_score": 4.34,
|
|
250
|
+
"avg_session_duration_sec": 45.2,
|
|
251
|
+
"end_type_counts": { "USER_ENDED": 5, "AGENT_ENDED": 10, "UNKNOWN": 21 },
|
|
252
|
+
"quality_distribution": { "5": 20, "4": 6, "3": 4, "2": 1, "1": 1 },
|
|
253
|
+
"abandonment_rate": 0.14,
|
|
254
|
+
"deflection_rate": 0.28,
|
|
255
|
+
"escalation_rate": 0.0,
|
|
256
|
+
"top_intents": { "I want help finding homes in San Jose.": 3, "Check order status": 2 },
|
|
257
|
+
"avg_faithfulness": 0.85,
|
|
258
|
+
"avg_answer_relevance": 0.72,
|
|
259
|
+
"avg_context_precision": 0.91,
|
|
260
|
+
"unavailable_dmos": []
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Key signals:
|
|
265
|
+
- `avg_quality_score` < 4.0 -> agent has Medium/Low quality responses, investigate low-scoring moments. Score labels: 5=High, 3-4=Medium, 2=Low, 1=Very Low
|
|
266
|
+
- `quality_distribution` skewed toward 1-3 -> systemic agent quality issue; focus on moments with score <= 3
|
|
267
|
+
- High `abandonment_rate` (> 0.3) -> users giving up, check for dead-ends or missing actions
|
|
268
|
+
- Low `avg_faithfulness` / `avg_answer_relevance` -> RAG retrieval issues, check knowledge base content
|
|
269
|
+
- `top_intents` shows what users ask about most -- verify the agent has topics/actions for each
|
|
270
|
+
- `unavailable_dmos` lists any DMOs that couldn't be queried (graceful degradation)
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Get Moment Insights (Per-Session Detail)
|
|
275
|
+
|
|
276
|
+
For deeper analysis of specific sessions, use `getMomentInsights()` to get intent summaries, moment durations, and retriever quality metrics per session.
|
|
277
|
+
|
|
278
|
+
```apex
|
|
279
|
+
String result = AgentforceOptimizeService.getMomentInsights(
|
|
280
|
+
'DATA_SPACE',
|
|
281
|
+
new List<String>{ 'SESSION_ID_1', 'SESSION_ID_2' }
|
|
282
|
+
);
|
|
283
|
+
System.debug('STDM_RESULT:' + result);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Returns a JSON array of `SessionInsights` objects:
|
|
287
|
+
```json
|
|
288
|
+
[
|
|
289
|
+
{
|
|
290
|
+
"session_id": "...",
|
|
291
|
+
"start_time": "...", "end_time": "...", "end_type": null,
|
|
292
|
+
"duration_ms": null, "turn_count": 3, "moment_count": 2,
|
|
293
|
+
"avg_quality_score": 4.5,
|
|
294
|
+
"action_error_count": 0,
|
|
295
|
+
"moments": [
|
|
296
|
+
{
|
|
297
|
+
"moment_id": "...",
|
|
298
|
+
"session_id": "...",
|
|
299
|
+
"start_time": "...", "end_time": "...", "duration_ms": 10000,
|
|
300
|
+
"request_summary": "I want help finding homes in San Jose.",
|
|
301
|
+
"response_summary": "The agent provided details on three homes...",
|
|
302
|
+
"agent_api_name": "MyServiceAgent",
|
|
303
|
+
"agent_version": null,
|
|
304
|
+
"quality_score": 5,
|
|
305
|
+
"quality_reasoning": "The agent provided a detailed and helpful response..."
|
|
306
|
+
}
|
|
307
|
+
],
|
|
308
|
+
"retriever_metrics": [],
|
|
309
|
+
"debug_message": null
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Key fields:
|
|
315
|
+
- `quality_score` (1-5) -- per-moment quality score from `AiAgentTagAssociation -> AiAgentTag.Value`. Maps to UI labels: 5=High, 3-4=Medium, 2=Low, 1=Very Low
|
|
316
|
+
- `quality_reasoning` -- LLM-generated explanation for the score (from `AssociationReasonText`)
|
|
317
|
+
- `avg_quality_score` -- session-level average across all scored moments
|
|
318
|
+
- `request_summary` / `response_summary` -- LLM-generated intent and response summaries per moment
|
|
319
|
+
- `moment_count` vs `turn_count` -- if `turn_count` >> `moment_count`, the agent needed many turns per intent (inefficient)
|
|
320
|
+
- `retriever_metrics` -- RAG quality scores per retrieval (empty if agent doesn't use knowledge retrieval)
|
|
321
|
+
- `debug_message` -- non-null if a DMO was unavailable (e.g. "AiAgentMoment DMO not available in this org")
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Run Observability Queries (RAG Deep-Dive)
|
|
326
|
+
|
|
327
|
+
For targeted RAG/retriever quality analysis, use the `@InvocableMethod` entry point `runObservabilityQuery()`. This can be called from anonymous Apex, Flows, or Agentforce actions. It queries Data Lake objects (`*__dll`) directly without a Data Space parameter.
|
|
328
|
+
|
|
329
|
+
**Query types:**
|
|
330
|
+
|
|
331
|
+
| `queryType` | What it returns |
|
|
332
|
+
|---|---|
|
|
333
|
+
| `KnowledgeGap` | Avg context precision + answer relevancy by topic/agent (lowest first) |
|
|
334
|
+
| `Hallucination` | Topics with avg faithfulness < 0.8 |
|
|
335
|
+
| `RetrievalQuality` | Avg context precision by retriever/topic/agent |
|
|
336
|
+
| `AnswerRelevancy` | Topics with avg answer relevancy < 0.7 |
|
|
337
|
+
| `Leaderboard` | Combined precision, relevancy, and faithfulness by topic/agent |
|
|
338
|
+
|
|
339
|
+
**From anonymous Apex:**
|
|
340
|
+
|
|
341
|
+
```apex
|
|
342
|
+
AgentforceOptimizeService.ObservabilityInput inp = new AgentforceOptimizeService.ObservabilityInput();
|
|
343
|
+
inp.queryType = 'KnowledgeGap';
|
|
344
|
+
inp.agentApiName = 'AGENT_API_NAME'; // optional
|
|
345
|
+
inp.topicApiName = 'TOPIC_API_NAME'; // optional
|
|
346
|
+
inp.lookbackDays = 90; // optional, default 90
|
|
347
|
+
|
|
348
|
+
List<AgentforceOptimizeService.ObservabilityOutput> results =
|
|
349
|
+
AgentforceOptimizeService.runObservabilityQuery(
|
|
350
|
+
new List<AgentforceOptimizeService.ObservabilityInput>{ inp }
|
|
351
|
+
);
|
|
352
|
+
System.debug('STDM_RESULT:' + results[0].summaryText);
|
|
353
|
+
System.debug('STDM_RESULT:' + results[0].resultJson);
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
sf apex run --json --file /tmp/observability_query.apex -o <org>
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**When to use observability queries vs `getAggregatedMetrics()`:**
|
|
361
|
+
|
|
362
|
+
- Use `getAggregatedMetrics()` for a broad health dashboard (session rates, top intents, overall RAG averages)
|
|
363
|
+
- Use `runObservabilityQuery()` for targeted RAG deep-dives when knowledge gaps or hallucination issues are detected -- it provides per-topic and per-retriever breakdowns
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Reconstruct Conversations
|
|
368
|
+
|
|
369
|
+
For each session, render the turn-by-turn timeline from the `ConversationData` JSON:
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
Session <session_id> [<channel>] <duration_ms>ms total <turn_count> turns
|
|
373
|
+
------------------------------------------------------------
|
|
374
|
+
Turn 1 [Topic: <topic>] <duration_ms>ms
|
|
375
|
+
User: <messages[type=Input].text>
|
|
376
|
+
Agent: <messages[type=Output].text>
|
|
377
|
+
Steps:
|
|
378
|
+
TOPIC_STEP: <name>
|
|
379
|
+
LLM_STEP: <name> (<duration_ms>ms)
|
|
380
|
+
ACTION_STEP: <name> in: <input> out: <output> [ERROR: <error>]
|
|
381
|
+
```
|