@salesforce/sfdx-agent-chat-generations 0.0.1
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 +10 -0
- package/LICENSE.txt +21 -0
- package/README.md +133 -0
- package/dist/chat-generations-language-model.d.ts +16 -0
- package/dist/chat-generations-language-model.js +402 -0
- package/dist/chat-generations-resolver.d.ts +72 -0
- package/dist/chat-generations-resolver.js +78 -0
- package/dist/chat-request.d.ts +117 -0
- package/dist/chat-request.js +14 -0
- package/dist/chat-response.d.ts +119 -0
- package/dist/chat-response.js +21 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +18 -0
- package/dist/gpt5-response-processor.d.ts +6 -0
- package/dist/gpt5-response-processor.js +189 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +52 -0
- package/dist/response-processor.d.ts +5 -0
- package/dist/response-processor.js +6 -0
- package/dist/sse-parser.d.ts +53 -0
- package/dist/sse-parser.js +116 -0
- package/dist/tool-arg-normalize.d.ts +1 -0
- package/dist/tool-arg-normalize.js +10 -0
- package/package.json +67 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
// W-23560954: GovCloud `chat/generations` fallback exports.
|
|
6
|
+
export { buildChatGenerationsLanguageModel } from './chat-generations-language-model.js';
|
|
7
|
+
export { ChatGenerationsResolver, CHAT_GENERATIONS_PROVIDER_HINT } from './chat-generations-resolver.js';
|
|
8
|
+
import { buildChatGenerationsLanguageModel } from './chat-generations-language-model.js';
|
|
9
|
+
import { ChatGenerationsResolver, CHAT_GENERATIONS_PROVIDER_HINT, } from './chat-generations-resolver.js';
|
|
10
|
+
/**
|
|
11
|
+
* Convenience factory for constructing the GovCloud `chat/generations` fallback wiring.
|
|
12
|
+
* Returns a `{ connectivityResolver, languageModelBuilders }` object ready to spread into
|
|
13
|
+
* `createAgentManager` and `MastraHarnessFactory` constructors (W-23560954).
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* This fallback routes all model traffic through the legacy GovCloud `chat/generations`
|
|
17
|
+
* wire shape. The consumer MUST set `AgentConfig.modelId` to a GovCloud-provisioned GPT
|
|
18
|
+
* model (e.g., `sfdc_ai__DefaultGPT4_8`) — the SDK default (Claude Sonnet 4.6) will not
|
|
19
|
+
* resolve in GovCloud. The resolver decorator flips the delegate's `baseUrl` and
|
|
20
|
+
* `providerHint` onto the GovCloud path, and the injected language-model builder speaks
|
|
21
|
+
* the Salesforce-proprietary `chat/generations` wire contract.
|
|
22
|
+
*
|
|
23
|
+
* **This package is temporary** and will be deleted once the Responses API is onboarded
|
|
24
|
+
* in GovCloud (expected within a few weeks).
|
|
25
|
+
*
|
|
26
|
+
* @param options - Configuration for the resolver decorator (delegate + GovCloud base URL +
|
|
27
|
+
* optional extra headers + optional enabled gate).
|
|
28
|
+
* @returns A `ChatGenerationsFallback` bag carrying both the resolver and builder map,
|
|
29
|
+
* typed for direct assignability to the manager + factory.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const { connectivityResolver, languageModelBuilders } = createChatGenerationsFallback({
|
|
34
|
+
* delegate: myExistingResolver,
|
|
35
|
+
* baseUrl: 'https://dev.api.gov.salesforce.com/ai/gpt/v1',
|
|
36
|
+
* extraHeaders: { 'x-salesforce-region': 'us-gov-east-1' }, // VERIFY: region header requirement
|
|
37
|
+
* });
|
|
38
|
+
* const factory = new MastraHarnessFactory({ languageModelBuilders });
|
|
39
|
+
* const manager = await createAgentManager(storageRoot, factory, { connectivityResolver });
|
|
40
|
+
* // Agent MUST bind a GovCloud-provisioned GPT model:
|
|
41
|
+
* const agent = await manager.createAgent(projectRoot, { modelId: 'sfdc_ai__DefaultGPT4_8', ... });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function createChatGenerationsFallback(options) {
|
|
45
|
+
return {
|
|
46
|
+
connectivityResolver: new ChatGenerationsResolver(options),
|
|
47
|
+
languageModelBuilders: {
|
|
48
|
+
[CHAT_GENERATIONS_PROVIDER_HINT]: buildChatGenerationsLanguageModel,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ChatResponseData, ChatStreamChunk, RawChatChunk } from './chat-response.js';
|
|
2
|
+
export interface ResponseProcessor {
|
|
3
|
+
processRawChatStream(rawStream: AsyncGenerator<RawChatChunk>): AsyncGenerator<ChatStreamChunk>;
|
|
4
|
+
processRawChatResponse(raw: RawChatChunk): ChatResponseData;
|
|
5
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter all events that aren't generations or errors
|
|
3
|
+
*
|
|
4
|
+
* See: https://git.soma.salesforce.com/pages/tech-enablement/einstein/docs/gateway/streaming/#how-it-works
|
|
5
|
+
*/
|
|
6
|
+
export declare function shouldSkipEvent(event: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Check if this is an error event from the gateway.
|
|
9
|
+
*
|
|
10
|
+
* See: https://git.soma.salesforce.com/pages/tech-enablement/einstein/docs/gateway/streaming/#error-chunks
|
|
11
|
+
*/
|
|
12
|
+
export declare function isErrorEvent(event: string | undefined): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Creates an SSE event handler for parsing LLMG API responses.
|
|
15
|
+
* This handler is shared between the streaming client and test utilities.
|
|
16
|
+
*
|
|
17
|
+
* @param queue - Array to push parsed chunks into
|
|
18
|
+
* @param onDone - Optional callback when [DONE] sentinel is received
|
|
19
|
+
* @param onParseError - Optional callback invoked when a chunk fails to parse. The callback
|
|
20
|
+
* receives the (truncated) raw chunk and a short reason string so consumers can surface a
|
|
21
|
+
* log or metric without the parser depending on a logging bus.
|
|
22
|
+
* @returns Event handler function for eventsource-parser
|
|
23
|
+
*/
|
|
24
|
+
export declare function createSSEEventHandler<T>(queue: T[], onDone?: () => void, onParseError?: (ctx: {
|
|
25
|
+
chunk: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}) => void): (event: {
|
|
28
|
+
event?: string;
|
|
29
|
+
data?: string;
|
|
30
|
+
}) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Parses raw SSE event strings into array of parsed objects.
|
|
33
|
+
* Used for testing - synchronous version that processes complete SSE string.
|
|
34
|
+
*
|
|
35
|
+
* This function uses the same parsing logic as RealLLMGatewayClient.requestStream()
|
|
36
|
+
* to ensure tests validate the production parser behavior.
|
|
37
|
+
*
|
|
38
|
+
* @param sseString - Raw SSE events (e.g., "event: generation\ndata: {...}\n\n")
|
|
39
|
+
* @returns Array of parsed objects (RawChatChunk or error objects)
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const chunks = parseSSEString<RawChatChunk>(`
|
|
44
|
+
* event: generation
|
|
45
|
+
* data: {"id":"test","generation_details":{"generations":[{"role":"assistant","content":"Hello"}],"parameters":{"provider":"openai"}}}
|
|
46
|
+
*
|
|
47
|
+
* event: generation
|
|
48
|
+
* data: [DONE]
|
|
49
|
+
*
|
|
50
|
+
* `);
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseSSEString<T>(sseString: string): T[];
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
// Ported from 3f694898^:packages/llm-gateway-sdk/src/sse-parser.ts (W-23560954).
|
|
6
|
+
import { createParser } from 'eventsource-parser';
|
|
7
|
+
/**
|
|
8
|
+
* Filter all events that aren't generations or errors
|
|
9
|
+
*
|
|
10
|
+
* See: https://git.soma.salesforce.com/pages/tech-enablement/einstein/docs/gateway/streaming/#how-it-works
|
|
11
|
+
*/
|
|
12
|
+
export function shouldSkipEvent(event) {
|
|
13
|
+
return !['generation', 'error'].includes(event);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if this is an error event from the gateway.
|
|
17
|
+
*
|
|
18
|
+
* See: https://git.soma.salesforce.com/pages/tech-enablement/einstein/docs/gateway/streaming/#error-chunks
|
|
19
|
+
*/
|
|
20
|
+
export function isErrorEvent(event) {
|
|
21
|
+
return event === 'error';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates an SSE event handler for parsing LLMG API responses.
|
|
25
|
+
* This handler is shared between the streaming client and test utilities.
|
|
26
|
+
*
|
|
27
|
+
* @param queue - Array to push parsed chunks into
|
|
28
|
+
* @param onDone - Optional callback when [DONE] sentinel is received
|
|
29
|
+
* @param onParseError - Optional callback invoked when a chunk fails to parse. The callback
|
|
30
|
+
* receives the (truncated) raw chunk and a short reason string so consumers can surface a
|
|
31
|
+
* log or metric without the parser depending on a logging bus.
|
|
32
|
+
* @returns Event handler function for eventsource-parser
|
|
33
|
+
*/
|
|
34
|
+
export function createSSEEventHandler(queue, onDone, onParseError) {
|
|
35
|
+
let done = false;
|
|
36
|
+
return ({ event, data }) => {
|
|
37
|
+
// Stop processing events after DONE sentinel
|
|
38
|
+
if (done)
|
|
39
|
+
return;
|
|
40
|
+
if (!data || !event)
|
|
41
|
+
return;
|
|
42
|
+
if (shouldSkipEvent(event))
|
|
43
|
+
return;
|
|
44
|
+
// Handle error events from the gateway - add to queue wrapped in error object
|
|
45
|
+
if (isErrorEvent(event)) {
|
|
46
|
+
try {
|
|
47
|
+
const errorData = JSON.parse(data);
|
|
48
|
+
queue.push({
|
|
49
|
+
error: errorData,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Malformed error data - create a parse error event
|
|
54
|
+
queue.push({
|
|
55
|
+
error: {
|
|
56
|
+
messageCode: 'E99999',
|
|
57
|
+
errorCode: 'PARSE_ERROR',
|
|
58
|
+
message: `Failed to parse error event: ${data}`,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
onParseError?.({ chunk: truncateChunk(data), reason: 'malformed error event JSON' });
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const trimmed = data.trim();
|
|
66
|
+
// Stop parsing when DONE sentinel is received
|
|
67
|
+
if (trimmed === '[DONE]' || trimmed === 'DONE') {
|
|
68
|
+
done = true;
|
|
69
|
+
onDone?.();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(data);
|
|
74
|
+
queue.push(parsed);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
onParseError?.({ chunk: truncateChunk(data), reason: 'unparseable generation chunk' });
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function truncateChunk(chunk, max = 200) {
|
|
82
|
+
return chunk.length > max ? `${chunk.slice(0, max)}…` : chunk;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parses raw SSE event strings into array of parsed objects.
|
|
86
|
+
* Used for testing - synchronous version that processes complete SSE string.
|
|
87
|
+
*
|
|
88
|
+
* This function uses the same parsing logic as RealLLMGatewayClient.requestStream()
|
|
89
|
+
* to ensure tests validate the production parser behavior.
|
|
90
|
+
*
|
|
91
|
+
* @param sseString - Raw SSE events (e.g., "event: generation\ndata: {...}\n\n")
|
|
92
|
+
* @returns Array of parsed objects (RawChatChunk or error objects)
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const chunks = parseSSEString<RawChatChunk>(`
|
|
97
|
+
* event: generation
|
|
98
|
+
* data: {"id":"test","generation_details":{"generations":[{"role":"assistant","content":"Hello"}],"parameters":{"provider":"openai"}}}
|
|
99
|
+
*
|
|
100
|
+
* event: generation
|
|
101
|
+
* data: [DONE]
|
|
102
|
+
*
|
|
103
|
+
* `);
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export function parseSSEString(sseString) {
|
|
107
|
+
const queue = [];
|
|
108
|
+
// Create the parser using the shared event handler
|
|
109
|
+
const parser = createParser({
|
|
110
|
+
onEvent: createSSEEventHandler(queue),
|
|
111
|
+
});
|
|
112
|
+
// Feed the entire SSE string to the parser
|
|
113
|
+
parser.feed(sseString);
|
|
114
|
+
return queue;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=sse-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizeToolArguments(args: string | null | undefined): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
// Ported from 3f694898^:packages/llm-gateway-sdk/src/models/tool-arg-normalize.ts (W-23560954).
|
|
6
|
+
// Normalize empty/null/undefined tool-call args to "{}" so consumers can JSON.parse.
|
|
7
|
+
export function normalizeToolArguments(args) {
|
|
8
|
+
return args ? args : '{}';
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=tool-arg-normalize.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salesforce/sfdx-agent-chat-generations",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Temporary GovCloud chat/generations fallback for @salesforce/sfdx-agent-harness-mastra",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc --build",
|
|
13
|
+
"clean": "tsc --build --clean",
|
|
14
|
+
"clean:all": "npm run clean && rimraf node_modules",
|
|
15
|
+
"postclean": "rimraf coverage && rimraf dist",
|
|
16
|
+
"format": "prettier --write .",
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"lint:fix": "eslint . --fix",
|
|
19
|
+
"showcoverage": "open ./coverage/lcov-report/index.html",
|
|
20
|
+
"test": "tsc --build ./test/tsconfig.json && vitest run --coverage"
|
|
21
|
+
},
|
|
22
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"!dist/**/*.map",
|
|
26
|
+
"!dist/test",
|
|
27
|
+
"CHANGELOG.md",
|
|
28
|
+
"LICENSE.txt"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@ai-sdk/provider": "^3.0.10",
|
|
32
|
+
"eventsource-parser": "^3.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@salesforce/sfdx-agent-sdk": "0.37.0",
|
|
36
|
+
"@salesforce/sfdx-agent-harness-mastra": "0.36.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
40
|
+
"@salesforce/sfdx-agent-sdk": "0.37.0",
|
|
41
|
+
"@salesforce/sfdx-agent-harness-mastra": "0.36.0",
|
|
42
|
+
"@types/node": "^22.20.0",
|
|
43
|
+
"@vitest/coverage-istanbul": "^4.1.10",
|
|
44
|
+
"@vitest/eslint-plugin": "^1.6.22",
|
|
45
|
+
"eslint": "^10.7.0",
|
|
46
|
+
"eslint-config-prettier": "^10.1.8",
|
|
47
|
+
"eslint-import-resolver-typescript": "^4.4.5",
|
|
48
|
+
"eslint-plugin-import": "^2.32.0",
|
|
49
|
+
"eslint-plugin-n": "^18.2.1",
|
|
50
|
+
"globals": "^17.6.0",
|
|
51
|
+
"lint-staged": "^17.0.7",
|
|
52
|
+
"prettier": "^3.9.4",
|
|
53
|
+
"rimraf": "^6.1.3",
|
|
54
|
+
"tsx": "^4.23.0",
|
|
55
|
+
"typescript": "^6.0.3",
|
|
56
|
+
"typescript-eslint": "^8.63.0",
|
|
57
|
+
"vitest": "^4.1.8"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=22.22.0"
|
|
61
|
+
},
|
|
62
|
+
"lint-staged": {
|
|
63
|
+
"*.{js,jsx,ts,tsx,json,md}": [
|
|
64
|
+
"prettier --write"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|