@salesforce/agentic-common 0.11.0 → 0.13.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/CHANGELOG.md +14 -0
- package/README.md +63 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/proxy-dispatcher.d.ts +39 -0
- package/dist/proxy-dispatcher.js +63 -0
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes to `@salesforce/agentic-common` are documented in this file.
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
5
|
|
|
6
|
+
## [0.13.0] - 2026-06-24
|
|
7
|
+
|
|
8
|
+
### Chores
|
|
9
|
+
- update dependencies and disable Mastra PostHog telemetry @W-23054815 ([#619](https://github.com/forcedotcom/agentic-dx/pull/619))
|
|
10
|
+
- **deps-dev**: bump @types/node from 22.19.21 to 22.20.0 in the dev-dependencies group ([#613](https://github.com/forcedotcom/agentic-dx/pull/613))
|
|
11
|
+
|
|
12
|
+
## [0.12.0] - 2026-06-22
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
- **agentic-common,harnesses**: route HTTPS_PROXY via injectable undici Dispatcher @W-23121596 ([#610](https://github.com/forcedotcom/agentic-dx/pull/610))
|
|
16
|
+
|
|
17
|
+
### Docs
|
|
18
|
+
- align SDK + agentic-common docs with current public surface (post-PR-#607) ([#608](https://github.com/forcedotcom/agentic-dx/pull/608))
|
|
19
|
+
|
|
6
20
|
## [0.11.0] - 2026-06-19
|
|
7
21
|
|
|
8
22
|
### Features
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Shared primitives and common utilities for the Salesforce agentic DX packages. Provides a typed event bus, clock
|
|
4
4
|
abstraction, ID generation, error utilities, log record shape, thin log-emit helpers, a Salesforce org connection
|
|
5
|
-
interface, and the `JSONWebToken` family used by
|
|
5
|
+
interface, and the `JSONWebToken` family used by the agent-SDK's connectivity resolvers.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
@@ -158,6 +158,30 @@ try {
|
|
|
158
158
|
}
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
### `resolveProxyDispatcher()` / `createProxyAwareFetch(dispatcher?)`
|
|
162
|
+
|
|
163
|
+
Proxy-routing helpers for Node's `fetch`. `resolveProxyDispatcher()` returns an `undici.EnvHttpProxyAgent` built from
|
|
164
|
+
`HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` env vars (or their lowercase forms — undici honors both casings), or
|
|
165
|
+
`undefined` when none is set. `createProxyAwareFetch(dispatcher?)` returns a `fetch`-compatible function that routes
|
|
166
|
+
outbound calls through the supplied dispatcher via `undici.fetch`; when `dispatcher` is `undefined`, it returns
|
|
167
|
+
`globalThis.fetch` unchanged so the no-proxy path has zero overhead.
|
|
168
|
+
|
|
169
|
+
Designed to be called from harness factories' `create()`; consumers normally don't call them directly. Both production
|
|
170
|
+
harness factories (`MastraHarnessFactory`, `ClaudeHarnessFactory`) build a proxy-aware fetch via these helpers and
|
|
171
|
+
thread it into every in-process HTTP call site (LLM gateway language-model builders + MCP remote transports). No
|
|
172
|
+
`globalThis` mutation.
|
|
173
|
+
|
|
174
|
+
`EnvHttpProxyAgent` captures `HTTPS_PROXY` and `HTTP_PROXY` at construction; `NO_PROXY` is re-evaluated per dispatch.
|
|
175
|
+
Set `HTTPS_PROXY` / `HTTP_PROXY` BEFORE the first `create()` call so the dispatcher snapshot reflects the right values.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { createProxyAwareFetch, resolveProxyDispatcher } from '@salesforce/agentic-common';
|
|
179
|
+
|
|
180
|
+
const dispatcher = resolveProxyDispatcher();
|
|
181
|
+
const fetchFn = createProxyAwareFetch(dispatcher);
|
|
182
|
+
await fetchFn('https://example.com/v1/things');
|
|
183
|
+
```
|
|
184
|
+
|
|
161
185
|
### `UniqueIDGenerator` / `UUIDGenerator`
|
|
162
186
|
|
|
163
187
|
Interface + default implementation for generating unique identifiers. Tests can inject deterministic implementations.
|
|
@@ -258,10 +282,13 @@ function createJWT(options: {
|
|
|
258
282
|
// Same fail-fast first-mint behavior, but uses an existing OrgConnection.
|
|
259
283
|
function createJWTFromConnection(
|
|
260
284
|
orgConnection: OrgConnection,
|
|
261
|
-
options?: { mintingPath?: string; featureId?: string }
|
|
285
|
+
options?: CreateJWTFromConnectionOptions, // { mintingPath?: string; featureId?: string }
|
|
262
286
|
): Promise<JSONWebToken>;
|
|
263
287
|
```
|
|
264
288
|
|
|
289
|
+
`JWTOptions`, `CreateJWTFromConnectionOptions`, `RequiredJWTHeaders`, and `RequiredJWTPayload` are all exported types so
|
|
290
|
+
consumers can name the parameter / generic-instantiation shapes without redeclaring them.
|
|
291
|
+
|
|
265
292
|
JWT lifecycle log records flow through `onLog`. The token's auto-refresh emits `'Refreshing expired JWT'` (debug),
|
|
266
293
|
`'JWT refreshed'` (info, with `durationMs`), and `'JWT refresh failed'` (error, with the wrapped exception) so operators
|
|
267
294
|
have visibility without subscribing to a separate telemetry channel.
|
|
@@ -292,12 +319,30 @@ type RetryCallbacks<T> = {
|
|
|
292
319
|
isRetryableError?: (err: unknown) => boolean;
|
|
293
320
|
isRetryableResult?: (result: T) => boolean;
|
|
294
321
|
getRetryAfterMs?: (result: T) => number | undefined;
|
|
295
|
-
onRetry?: (info:
|
|
296
|
-
onExhausted?: (info:
|
|
322
|
+
onRetry?: (info: RetryAttemptInfo<T>) => void;
|
|
323
|
+
onExhausted?: (info: RetryExhaustedInfo<T>) => void;
|
|
297
324
|
drainResult?: (result: T) => Promise<void>;
|
|
298
325
|
};
|
|
326
|
+
|
|
327
|
+
type RetryAttemptInfo<T> = {
|
|
328
|
+
attempt: number; // 1-indexed attempt number that just failed
|
|
329
|
+
delayMs: number; // jittered or server-driven delay about to be waited
|
|
330
|
+
error?: unknown; // set if the attempt threw a retryable error
|
|
331
|
+
result?: T; // set if the attempt returned a retryable result
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
type RetryExhaustedInfo<T> = {
|
|
335
|
+
attempts: number; // total attempts made
|
|
336
|
+
error?: unknown;
|
|
337
|
+
result?: T;
|
|
338
|
+
reason: 'attempts' | 'deadline';
|
|
339
|
+
};
|
|
299
340
|
```
|
|
300
341
|
|
|
342
|
+
The fully-resolved defaults are exported as `DEFAULT_RETRY_OPTIONS`
|
|
343
|
+
(`{ maxAttempts: 3, initialDelayMs: 100, maxDelayMs: 2000, maxRetryAfterMs: 60_000, backoffFactor: 2, maxTotalElapsedMs: Infinity }`)
|
|
344
|
+
so consumers and tests can share one source of truth.
|
|
345
|
+
|
|
301
346
|
Use `BackoffRetryer` in production:
|
|
302
347
|
|
|
303
348
|
```typescript
|
|
@@ -369,6 +414,20 @@ import { backfillCreatedAt, RealClock } from '@salesforce/agentic-common';
|
|
|
369
414
|
const filled = backfillCreatedAt(messages, new RealClock());
|
|
370
415
|
```
|
|
371
416
|
|
|
417
|
+
### `buildSummaryPrompt(transcript: string): string`
|
|
418
|
+
|
|
419
|
+
Returns a third-person summarization-prompt string asking the model to compress the supplied transcript into a context
|
|
420
|
+
summary. Used by both production harnesses (`@salesforce/sfdx-agent-harness-mastra` /
|
|
421
|
+
`@salesforce/sfdx-agent-harness-claude`) inside their `compactThread` flows so the prompt wording stays uniform across
|
|
422
|
+
implementations — a freshly-summarized thread reads the same regardless of which harness produced it.
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { buildSummaryPrompt } from '@salesforce/agentic-common';
|
|
426
|
+
|
|
427
|
+
const prompt = buildSummaryPrompt(transcriptText);
|
|
428
|
+
// → "Summarize the following conversation into a concise context summary. ..."
|
|
429
|
+
```
|
|
430
|
+
|
|
372
431
|
## Development
|
|
373
432
|
|
|
374
433
|
See [DEVELOPING.md](../../DEVELOPING.md) for build-from-source setup, scripts, and monorepo commands.
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { type OrgConnectionFactory, RealOrgConnectionFactory } from './connectio
|
|
|
5
5
|
export { getErrorMessage, getErrorMessageWithStack, isAbortError, wrapError } from './error-utils.js';
|
|
6
6
|
export { EventBus, type EventListener, type SubscriberPresenceListener, type Unsubscribe } from './event-bus.js';
|
|
7
7
|
export { type UniqueIDGenerator, UUIDGenerator } from './id-generator.js';
|
|
8
|
+
export { createProxyAwareFetch, resolveProxyDispatcher } from './proxy-dispatcher.js';
|
|
8
9
|
export { type CreateJWTFromConnectionOptions, createJWT, createJWTFromConnection, DynamicJSONWebToken, FixedJSONWebToken, type JSONWebToken, type JWTOptions, type RequiredJWTHeaders, type RequiredJWTPayload, } from './jwt.js';
|
|
9
10
|
export { LogBus, type LogLevel, type LogRecord } from './log.js';
|
|
10
11
|
export { type FrontmatterSplit, splitFrontmatterAndBody } from './markdown-frontmatter.js';
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { RealOrgConnectionFactory } from './connection-factory.js';
|
|
|
9
9
|
export { getErrorMessage, getErrorMessageWithStack, isAbortError, wrapError } from './error-utils.js';
|
|
10
10
|
export { EventBus } from './event-bus.js';
|
|
11
11
|
export { UUIDGenerator } from './id-generator.js';
|
|
12
|
+
export { createProxyAwareFetch, resolveProxyDispatcher } from './proxy-dispatcher.js';
|
|
12
13
|
export { createJWT, createJWTFromConnection, DynamicJSONWebToken, FixedJSONWebToken, } from './jwt.js';
|
|
13
14
|
export { LogBus } from './log.js';
|
|
14
15
|
export { splitFrontmatterAndBody } from './markdown-frontmatter.js';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Dispatcher } from 'undici';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a `Dispatcher` from `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` env
|
|
4
|
+
* vars (either casing — undici honors both), or `undefined` when none is set.
|
|
5
|
+
*
|
|
6
|
+
* `EnvHttpProxyAgent` reads `HTTPS_PROXY` and `HTTP_PROXY` at construction and
|
|
7
|
+
* pins them for the dispatcher's lifetime; `NO_PROXY` is re-evaluated per
|
|
8
|
+
* dispatch (see undici v8.5 source: `#noProxyChanged` / `#noProxyEnv`). Callers
|
|
9
|
+
* must set `HTTPS_PROXY` / `HTTP_PROXY` BEFORE invoking this function; later
|
|
10
|
+
* mutations of those two are not picked up by the returned dispatcher.
|
|
11
|
+
*
|
|
12
|
+
* Returning `undefined` when no proxy env is set preserves the zero-wrap fast
|
|
13
|
+
* path in `createProxyAwareFetch` — `globalThis.fetch` is returned unchanged.
|
|
14
|
+
* Constructing an `EnvHttpProxyAgent` unconditionally would push every
|
|
15
|
+
* no-proxy harness through the undici-fetch wrapper.
|
|
16
|
+
*
|
|
17
|
+
* Designed to be called from harness factories' `create()` to derive a default
|
|
18
|
+
* proxy-aware dispatcher per harness instance.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveProxyDispatcher(): Dispatcher | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Returns a `fetch`-compatible function that routes through `dispatcher` (via
|
|
23
|
+
* `undici.fetch`). When `dispatcher` is `undefined`, returns `globalThis.fetch`
|
|
24
|
+
* unchanged so the no-proxy path has zero overhead and no undici-wrapper
|
|
25
|
+
* shape leaks into the call site.
|
|
26
|
+
*
|
|
27
|
+
* Composes with the harness fetch wrappers (`createGatewayFetch`,
|
|
28
|
+
* `createAuthFetch`): those wrappers add per-request header merging on top
|
|
29
|
+
* of whatever inner `fetch` they're handed. Routing the inner fetch through
|
|
30
|
+
* an undici `Dispatcher` is what makes `HTTPS_PROXY` honoring happen — without
|
|
31
|
+
* any process-wide `setGlobalDispatcher` mutation.
|
|
32
|
+
*
|
|
33
|
+
* Verified against the SDKs we hand a `fetch` option to today
|
|
34
|
+
* (`@anthropic-ai/sdk`, `@anthropic-ai/bedrock-sdk`, `openai`, `@mastra/mcp`
|
|
35
|
+
* via `@modelcontextprotocol/sdk` `StreamableHTTPClientTransport`): every
|
|
36
|
+
* outbound HTTP call (including streaming SSE) routes through the injected
|
|
37
|
+
* `fetch`. See PR #609 for the SDK source-trace findings.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createProxyAwareFetch(dispatcher?: Dispatcher): typeof fetch;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
import { Dispatcher, EnvHttpProxyAgent, fetch as undiciFetch } from 'undici';
|
|
6
|
+
/**
|
|
7
|
+
* Resolves a `Dispatcher` from `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` env
|
|
8
|
+
* vars (either casing — undici honors both), or `undefined` when none is set.
|
|
9
|
+
*
|
|
10
|
+
* `EnvHttpProxyAgent` reads `HTTPS_PROXY` and `HTTP_PROXY` at construction and
|
|
11
|
+
* pins them for the dispatcher's lifetime; `NO_PROXY` is re-evaluated per
|
|
12
|
+
* dispatch (see undici v8.5 source: `#noProxyChanged` / `#noProxyEnv`). Callers
|
|
13
|
+
* must set `HTTPS_PROXY` / `HTTP_PROXY` BEFORE invoking this function; later
|
|
14
|
+
* mutations of those two are not picked up by the returned dispatcher.
|
|
15
|
+
*
|
|
16
|
+
* Returning `undefined` when no proxy env is set preserves the zero-wrap fast
|
|
17
|
+
* path in `createProxyAwareFetch` — `globalThis.fetch` is returned unchanged.
|
|
18
|
+
* Constructing an `EnvHttpProxyAgent` unconditionally would push every
|
|
19
|
+
* no-proxy harness through the undici-fetch wrapper.
|
|
20
|
+
*
|
|
21
|
+
* Designed to be called from harness factories' `create()` to derive a default
|
|
22
|
+
* proxy-aware dispatcher per harness instance.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveProxyDispatcher() {
|
|
25
|
+
if (!process.env['HTTPS_PROXY'] &&
|
|
26
|
+
!process.env['HTTP_PROXY'] &&
|
|
27
|
+
!process.env['https_proxy'] &&
|
|
28
|
+
!process.env['http_proxy']) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
return new EnvHttpProxyAgent();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns a `fetch`-compatible function that routes through `dispatcher` (via
|
|
35
|
+
* `undici.fetch`). When `dispatcher` is `undefined`, returns `globalThis.fetch`
|
|
36
|
+
* unchanged so the no-proxy path has zero overhead and no undici-wrapper
|
|
37
|
+
* shape leaks into the call site.
|
|
38
|
+
*
|
|
39
|
+
* Composes with the harness fetch wrappers (`createGatewayFetch`,
|
|
40
|
+
* `createAuthFetch`): those wrappers add per-request header merging on top
|
|
41
|
+
* of whatever inner `fetch` they're handed. Routing the inner fetch through
|
|
42
|
+
* an undici `Dispatcher` is what makes `HTTPS_PROXY` honoring happen — without
|
|
43
|
+
* any process-wide `setGlobalDispatcher` mutation.
|
|
44
|
+
*
|
|
45
|
+
* Verified against the SDKs we hand a `fetch` option to today
|
|
46
|
+
* (`@anthropic-ai/sdk`, `@anthropic-ai/bedrock-sdk`, `openai`, `@mastra/mcp`
|
|
47
|
+
* via `@modelcontextprotocol/sdk` `StreamableHTTPClientTransport`): every
|
|
48
|
+
* outbound HTTP call (including streaming SSE) routes through the injected
|
|
49
|
+
* `fetch`. See PR #609 for the SDK source-trace findings.
|
|
50
|
+
*/
|
|
51
|
+
export function createProxyAwareFetch(dispatcher) {
|
|
52
|
+
if (!dispatcher)
|
|
53
|
+
return globalThis.fetch;
|
|
54
|
+
// Cast at the boundary: Node's `fetch` and undici's `fetch` have structurally-
|
|
55
|
+
// identical RequestInfo / Response shapes but TS treats them as distinct nominal
|
|
56
|
+
// types. Casting via `unknown` keeps the consumer-facing signature as
|
|
57
|
+
// `typeof fetch` (the WHATWG/Node type) while routing through undici under it.
|
|
58
|
+
return (input, init) => undiciFetch(input, {
|
|
59
|
+
...init,
|
|
60
|
+
dispatcher,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=proxy-dispatcher.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/agentic-common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Shared primitives and common utilities for the Salesforce agentic DX packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
"LICENSE.txt"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@salesforce/core": "^8.31.1"
|
|
33
|
+
"@salesforce/core": "^8.31.1",
|
|
34
|
+
"undici": "^8.5.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@eslint/js": "^10.0.1",
|
|
37
|
-
"@types/node": "^22.
|
|
38
|
+
"@types/node": "^22.20.0",
|
|
38
39
|
"@vitest/coverage-istanbul": "^4.1.8",
|
|
39
40
|
"@vitest/eslint-plugin": "^1.6.20",
|
|
40
41
|
"eslint": "^10.5.0",
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
"vitest": "^4.1.8"
|
|
52
53
|
},
|
|
53
54
|
"engines": {
|
|
54
|
-
"node": ">=22.
|
|
55
|
+
"node": ">=22.22.0"
|
|
55
56
|
},
|
|
56
57
|
"lint-staged": {
|
|
57
58
|
"*.{js,jsx,ts,tsx,json,md}": [
|