@sf-explorer/agentforce-service 1.0.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/README.md +173 -0
- package/bin/cli.js +43 -0
- package/dist/client/assets/index-4BXb_5Lv.css +1 -0
- package/dist/client/assets/index-CCE64qe5.js +43 -0
- package/dist/client/index.html +13 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +54 -0
- package/dist/openapi.d.ts +644 -0
- package/dist/openapi.js +475 -0
- package/dist/org.d.ts +21 -0
- package/dist/org.js +45 -0
- package/dist/routes/agents.d.ts +3 -0
- package/dist/routes/agents.js +181 -0
- package/dist/routes/context.d.ts +15 -0
- package/dist/routes/context.js +11 -0
- package/dist/routes/index.d.ts +5 -0
- package/dist/routes/index.js +13 -0
- package/dist/routes/session.d.ts +3 -0
- package/dist/routes/session.js +195 -0
- package/dist/routes/tests.d.ts +3 -0
- package/dist/routes/tests.js +211 -0
- package/dist/routes.d.ts +14 -0
- package/dist/routes.js +534 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# @sf-explorer/agentforce-service
|
|
2
|
+
|
|
3
|
+
Express server for Agentforce agent APIs. Exposes sendMessage, compile, get agent, and update agent endpoints. Initializes from `sf force:org:display --json`. Serves a bundled React UI when built.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
### Recommended: Run with npx
|
|
8
|
+
|
|
9
|
+
No install required. From your Salesforce project directory:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @sf-explorer/agentforce-service
|
|
13
|
+
npx @sf-explorer/agentforce-service /path/to/sf-project
|
|
14
|
+
npx @sf-explorer/agentforce-service . --org my-org --port 3847
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then open http://localhost:3847 for the UI.
|
|
18
|
+
|
|
19
|
+
### From source (development)
|
|
20
|
+
|
|
21
|
+
**From the repo root:**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install
|
|
25
|
+
npm run build
|
|
26
|
+
npm start -- example
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**From the server folder:**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd server
|
|
33
|
+
npm install
|
|
34
|
+
npm run build
|
|
35
|
+
npm start -- ../example
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Ensure you have an authenticated Salesforce org (`sf org login web` and `sf config set target-org <alias>`).
|
|
39
|
+
|
|
40
|
+
## Development (from repo)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Build (client + server)
|
|
44
|
+
npm run build
|
|
45
|
+
|
|
46
|
+
# Start server
|
|
47
|
+
npm start
|
|
48
|
+
npm start -- ../example
|
|
49
|
+
npm start -- ../example --org my-org --port 3847
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The build outputs the client to `dist/client` and compiles TypeScript to `dist/`. The UI is served at the root URL when the server runs.
|
|
53
|
+
|
|
54
|
+
### Install (optional)
|
|
55
|
+
|
|
56
|
+
For a global install: `npm install -g @sf-explorer/agentforce-service`, then run `agentforce-service [projectDir] [--org alias] [--port 3847]`.
|
|
57
|
+
|
|
58
|
+
## APIs
|
|
59
|
+
|
|
60
|
+
### Session flow (order matters)
|
|
61
|
+
|
|
62
|
+
1. **POST /api/startSession** → get `sessionId`
|
|
63
|
+
2. **POST /api/sendmessage** → chat (repeat as needed); response includes `messages[].planId`
|
|
64
|
+
3. **POST /api/trace** → (optional) get plan trace for a `planId` from sendmessage
|
|
65
|
+
4. **POST /api/endSession** → end session when done
|
|
66
|
+
|
|
67
|
+
### Endpoints
|
|
68
|
+
|
|
69
|
+
| Method | Path | Description |
|
|
70
|
+
|--------|------|-------------|
|
|
71
|
+
| POST | `/api/startSession` | Start agent preview (agentBundleName or apiNameOrId) |
|
|
72
|
+
| POST | `/api/sendmessage` | Send message via agent.preview.send() |
|
|
73
|
+
| POST | `/api/trace` | Get plan trace for a planId (from sendmessage response) |
|
|
74
|
+
| POST | `/api/endSession` | End preview session |
|
|
75
|
+
| POST | `/api/compile` | Compile AgentScript via ScriptAgent.compile() |
|
|
76
|
+
| GET | `/api/agents` | List agents (local, remote, or all previewable) |
|
|
77
|
+
| GET | `/api/agent/:developerName` | Retrieve agentscript metadata from Metadata API |
|
|
78
|
+
| PUT | `/api/agent/:developerName` | Deploy an agentscript package to the org |
|
|
79
|
+
| GET | `/api/tests` | List test definitions (local JSON files) |
|
|
80
|
+
| GET | `/api/tests/:filename` | Retrieve test content by filename |
|
|
81
|
+
| POST | `/api/tests/run` | Run test (Salesforce AI Evaluation or local JSON) |
|
|
82
|
+
| GET | `/api/tests/runs/:runId` | Retrieve test run status or results |
|
|
83
|
+
|
|
84
|
+
### startSession
|
|
85
|
+
|
|
86
|
+
Uses `@salesforce/agents` Agent.preview.start(). Pass either `agentBundleName` (script agent) or `apiNameOrId` (production agent). For script agents, optional `useMock` (default `true`) controls simulated vs live mode.
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
POST /api/startSession
|
|
90
|
+
{ "agentBundleName": "AgentScriptDemo" }
|
|
91
|
+
{ "agentBundleName": "AgentScriptDemo", "useMock": false }
|
|
92
|
+
// or
|
|
93
|
+
{ "apiNameOrId": "BotIdOrApiName" }
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### sendmessage
|
|
97
|
+
|
|
98
|
+
Uses `@salesforce/agents` agent.preview.send().
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
POST /api/sendmessage
|
|
102
|
+
{ "sessionId": "...", "message": "Hello" }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### trace
|
|
106
|
+
|
|
107
|
+
Uses `@salesforce/agents` agent.getTrace(planId). planId comes from sendmessage response `messages[].planId`. Requires an active session.
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
POST /api/trace
|
|
111
|
+
{ "sessionId": "...", "planId": "..." }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### endSession
|
|
115
|
+
|
|
116
|
+
Uses `@salesforce/agents` agent.preview.end().
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
POST /api/endSession
|
|
120
|
+
{ "sessionId": "..." }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### compile
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
POST /api/compile
|
|
127
|
+
{ "agentBundleName": "AgentScriptDemo" }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### retrieve agents
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
GET /api/agents?source=all # all previewable (default)
|
|
134
|
+
GET /api/agents?source=local # agent bundles in project
|
|
135
|
+
GET /api/agents?source=remote # published bots in org
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### get agent
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
GET /api/agent/AgentScriptDemo
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### update agent
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
PUT /api/agent/AgentScriptDemo
|
|
148
|
+
{ "sourcePath": "/optional/path/to/bundle" }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If `sourcePath` is omitted, uses `{projectDir}/force-app/main/default/aiAuthoringBundles/{developerName}`.
|
|
152
|
+
|
|
153
|
+
### tests
|
|
154
|
+
|
|
155
|
+
List, retrieve, and run agent tests.
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
GET /api/tests?dir=all # List test files (root + example/)
|
|
159
|
+
GET /api/tests/energy-test-case.json # Retrieve test content
|
|
160
|
+
POST /api/tests/run # Run test (see body options below)
|
|
161
|
+
GET /api/tests/runs/:runId # Get run status; ?results=true for full results
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Run options:**
|
|
165
|
+
|
|
166
|
+
- **Salesforce AI Evaluation** – `{ "aiEvaluationDefinitionName": "MyTestDef" }` → returns `{ runId }`; poll `/api/tests/runs/:runId` for status/results.
|
|
167
|
+
- **Local run** – `{ "testFile": "energy-test-case.json", "agentBundleName": "MyAgent" }` → executes test cases via preview session; returns `{ total, passed, failed, results }`.
|
|
168
|
+
|
|
169
|
+
## Prerequisites
|
|
170
|
+
|
|
171
|
+
- Node.js >= 18
|
|
172
|
+
- Salesforce CLI (`sf`) installed and authenticated
|
|
173
|
+
- A Salesforce project with `aiAuthoringBundles` (for compile/agent APIs)
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI entry point for @sf-explorer/agentforce-service
|
|
5
|
+
* Usage: npx @sf-explorer/agentforce-service [projectDir] [--org alias] [--port 3847]
|
|
6
|
+
*
|
|
7
|
+
* Starts the server in the given folder (or cwd). Initializes from sf force:org:display.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { resolve } from "path";
|
|
11
|
+
import { createServer } from "../dist/index.js";
|
|
12
|
+
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
let projectDir = process.cwd();
|
|
15
|
+
let orgAlias;
|
|
16
|
+
let port = 3847;
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < args.length; i++) {
|
|
19
|
+
if (args[i] === "--org" && args[i + 1]) {
|
|
20
|
+
orgAlias = args[++i];
|
|
21
|
+
} else if (args[i] === "--port" && args[i + 1]) {
|
|
22
|
+
port = parseInt(args[++i], 10) || 3847;
|
|
23
|
+
} else if (!args[i].startsWith("-")) {
|
|
24
|
+
projectDir = resolve(process.cwd(), args[i]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
createServer({ projectDir, orgAlias, port }).catch((err) => {
|
|
29
|
+
console.error("Org connection failed. Server will not start.");
|
|
30
|
+
console.error("");
|
|
31
|
+
console.error(err.message);
|
|
32
|
+
console.error("");
|
|
33
|
+
console.error(
|
|
34
|
+
"To fix: authenticate an org and set it as default, e.g.:"
|
|
35
|
+
);
|
|
36
|
+
console.error(" sf org login web");
|
|
37
|
+
console.error(" sf config set target-org <alias>");
|
|
38
|
+
console.error("");
|
|
39
|
+
console.error(
|
|
40
|
+
"Or pass an org alias: npx @sf-explorer/agentforce-service . --org <alias>"
|
|
41
|
+
);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{font-family:JetBrains Mono,SF Mono,Fira Code,monospace;line-height:1.5;font-weight:400;color:#e2e8f0;background:#0f172a}*{box-sizing:border-box}body{margin:0;min-height:100vh}#root{max-width:1200px;margin:0 auto;padding:1.5rem}h1,h2,h3{font-weight:600;margin:0 0 .75rem}h1{font-size:1.5rem;color:#38bdf8}h2{font-size:1.1rem;color:#94a3b8}h3{font-size:.95rem}button{font-family:inherit;font-size:.85rem;padding:.5rem 1rem;border-radius:6px;border:1px solid #334155;background:#1e293b;color:#e2e8f0;cursor:pointer;transition:background .15s,border-color .15s}button:hover{background:#334155;border-color:#475569}button:disabled{opacity:.5;cursor:not-allowed}input,textarea,select{font-family:inherit;font-size:.9rem;padding:.5rem .75rem;border-radius:6px;border:1px solid #334155;background:#1e293b;color:#e2e8f0;width:100%}input:focus,textarea:focus{outline:none;border-color:#38bdf8}label{display:block;font-size:.8rem;color:#94a3b8;margin-bottom:.25rem}.card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:1rem;margin-bottom:1rem}.response{font-size:.8rem;background:#0f172a;border:1px solid #334155;border-radius:6px;padding:.75rem;margin-top:.75rem;max-height:200px;overflow:auto;white-space:pre-wrap;word-break:break-all}.response.error{border-color:#f87171;color:#fca5a5}.response.success{border-color:#34d399}.agent-script-editor{width:100%;min-height:320px;font-size:.85rem;line-height:1.5;resize:vertical;margin-top:.25rem}.form-row{display:flex;gap:.75rem;align-items:flex-end;margin-bottom:.75rem}.form-row>*{flex:1}.form-row button{flex:0 0 auto}.chat-message{margin:.5rem 0;padding:.5rem;border-radius:6px;font-size:.9rem}.chat-message.user{background:#334155;margin-left:1rem}.chat-message.agent{background:#1e3a5f;margin-right:1rem}.chat-thread{margin-bottom:1rem;display:flex;flex-direction:column;gap:.75rem}.chat-message{display:flex;flex-direction:column;gap:.5rem}.trace-toggle{margin-top:.5rem}.trace-btn{font-size:.8rem;padding:.25rem .5rem;background:transparent;border:1px solid #475569;color:#94a3b8}.trace-btn:hover{color:#38bdf8;border-color:#38bdf8}.trace-panel{margin-top:.5rem;padding:.75rem;background:#0f172a;border:1px solid #334155;border-radius:6px;font-size:.8rem;max-height:400px;overflow-y:auto}.trace-meta{display:flex;flex-wrap:wrap;gap:1rem;margin-bottom:.75rem;padding-bottom:.5rem;border-bottom:1px solid #334155;color:#94a3b8}.trace-meta span{font-size:.85rem}.trace-steps{display:flex;flex-direction:column;gap:.5rem}.trace-step{padding:.5rem;border-radius:4px;border-left:3px solid #334155;background:#1e293b}.trace-step.user-input{border-left-color:#38bdf8}.trace-step.llm{border-left-color:#a78bfa}.trace-step.topic{border-left-color:#34d399}.trace-step.reasoning{border-left-color:#fbbf24}.trace-step.function{border-left-color:#f472b6}.trace-step.planner{border-left-color:#34d399}.trace-step.event{border-left-color:#94a3b8}.trace-step.event.error{border-left-color:#f87171}.trace-step-type{display:inline-block;font-weight:600;color:#94a3b8;margin-right:.5rem;min-width:4.5rem}.trace-step-content{color:#e2e8f0}.trace-details{margin-top:.5rem;font-size:.75rem}.trace-details summary{cursor:pointer;color:#94a3b8}.trace-details pre{margin:.25rem 0 0;padding:.5rem;background:#0f172a;border-radius:4px;overflow-x:auto;white-space:pre-wrap;word-break:break-word}.trace-empty{color:#94a3b8;margin:0;font-style:italic}.status-badge{display:inline-block;padding:.2rem .5rem;border-radius:4px;font-size:.75rem}.status-badge.connected{background:#065f46;color:#6ee7b7}.status-badge.disconnected{background:#7f1d1d;color:#fca5a5}.tabs{display:flex;gap:.25rem;margin-bottom:1.5rem;border-bottom:1px solid #334155}.tab{padding:.5rem 1rem;background:transparent;border:none;border-bottom:2px solid transparent;margin-bottom:-1px;color:#94a3b8;cursor:pointer}.tab:hover{color:#e2e8f0}.tab.active{color:#38bdf8;border-bottom-color:#38bdf8}.api-docs-section{min-height:600px}.api-docs-iframe{width:100%;min-height:70vh;border:1px solid #334155;border-radius:6px;background:#fff}.session-chat .chat-thread{max-width:720px}.session-chat .form-row input{max-width:400px}.test-cases-list{display:flex;flex-direction:column;gap:1rem}.test-case-card{padding:1rem;background:#0f172a;border:1px solid #334155;border-radius:8px;display:flex;flex-direction:column;gap:.5rem}.test-case-header{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.test-case-index{font-weight:600;color:#38bdf8;min-width:2rem}.test-case-id{font-size:.8rem;color:#64748b;background:#1e293b;padding:.15rem .4rem;border-radius:4px}.test-case-name{font-weight:500;color:#e2e8f0}.test-case-desc{font-size:.85rem;color:#94a3b8;margin:0;line-height:1.4}.test-case-messages{display:flex;flex-direction:column;gap:.35rem}.test-case-label{font-size:.75rem;color:#64748b;text-transform:uppercase;letter-spacing:.05em}.test-case-msg{font-size:.9rem;padding:.4rem .6rem;border-radius:4px;border-left:3px solid #334155}.test-case-msg.user{background:#1e293b;border-left-color:#38bdf8}.test-case-expected{font-size:.85rem;color:#a78bfa;padding:.4rem 0}.test-case-meta{font-size:.8rem;color:#64748b}.test-case-run-btn{align-self:flex-start;margin-top:.25rem;font-size:.8rem;padding:.35rem .75rem}
|