@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 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}