@salesforce/sfdx-agent-harness-openai 0.0.1 → 0.2.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 +35 -8
- package/README.md +15 -4
- package/dist/openai-agents-harness.d.ts +21 -11
- package/dist/openai-agents-harness.js +164 -78
- package/dist/openai-agents-harness.js.map +1 -1
- package/dist/openai-approval-coordinator.d.ts +66 -18
- package/dist/openai-approval-coordinator.js +127 -28
- package/dist/openai-approval-coordinator.js.map +1 -1
- package/dist/openai-built-in-policies.d.ts +4 -3
- package/dist/openai-built-in-policies.js +4 -3
- package/dist/openai-built-in-policies.js.map +1 -1
- package/dist/openai-event-adapter.d.ts +8 -3
- package/dist/openai-event-adapter.js +9 -4
- package/dist/openai-event-adapter.js.map +1 -1
- package/dist/openai-mcp-state.d.ts +22 -7
- package/dist/openai-message-mapper.d.ts +58 -9
- package/dist/openai-message-mapper.js +137 -12
- package/dist/openai-message-mapper.js.map +1 -1
- package/dist/openai-skill-tools.d.ts +36 -0
- package/dist/openai-skill-tools.js +209 -0
- package/dist/openai-skill-tools.js.map +1 -0
- package/dist/openai-tool-redaction.d.ts +44 -10
- package/dist/openai-tool-redaction.js +77 -29
- package/dist/openai-tool-redaction.js.map +1 -1
- package/dist/rule-composer.d.ts +35 -0
- package/dist/rule-composer.js +88 -0
- package/dist/rule-composer.js.map +1 -0
- package/dist/skill-loader.d.ts +76 -0
- package/dist/skill-loader.js +180 -0
- package/dist/skill-loader.js.map +1 -0
- package/dist/test/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type LogBus } from '@salesforce/agentic-common';
|
|
2
|
+
/**
|
|
3
|
+
* One discovered skill: the absolute path to its `SKILL.md` and the description
|
|
4
|
+
* string the loader surfaces to the model in the `load_skill` tool catalog. The
|
|
5
|
+
* frontmatter `name` (or the skill folder basename, if the frontmatter is
|
|
6
|
+
* missing) is the key in the {@link SkillMap}; this struct holds the rest.
|
|
7
|
+
*/
|
|
8
|
+
export type SkillEntry = {
|
|
9
|
+
/** Absolute path to the resolved `SKILL.md` file. */
|
|
10
|
+
path: string;
|
|
11
|
+
/**
|
|
12
|
+
* Skill description from the YAML frontmatter `description:` field, trimmed.
|
|
13
|
+
* Empty string when the frontmatter omits `description:`. Surfaced verbatim
|
|
14
|
+
* in the `load_skill` tool description so the model can pick the right skill
|
|
15
|
+
* without reading the body.
|
|
16
|
+
*/
|
|
17
|
+
description: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Discovered skill catalog: skill name → entry. The name is what the model
|
|
21
|
+
* passes back when it invokes `load_skill({ skill })`.
|
|
22
|
+
*/
|
|
23
|
+
export type SkillMap = Map<string, SkillEntry>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve `config.skills` paths into a `Map<skillName, SkillEntry>`. Each entry
|
|
26
|
+
* in `skillPaths` may be:
|
|
27
|
+
*
|
|
28
|
+
* - A `SKILL.md` file path → one skill (named from frontmatter or parent folder
|
|
29
|
+
* basename).
|
|
30
|
+
* - A folder containing `SKILL.md` → one skill.
|
|
31
|
+
* - A parent folder containing one or more skill subfolders, each with its own
|
|
32
|
+
* `SKILL.md` → many skills. Subfolders without a `SKILL.md` are silently
|
|
33
|
+
* skipped so consumers can drop arbitrary subdirectories into their skill
|
|
34
|
+
* roots without breaking the loader.
|
|
35
|
+
*
|
|
36
|
+
* Each entry is resolved against `projectRoot` (via `path.resolve`) before it is
|
|
37
|
+
* `stat`ed, per the SDK `AgentConfig.skills` contract — relative entries resolve
|
|
38
|
+
* against the project root, absolute entries pass through unchanged. The
|
|
39
|
+
* resulting `SkillEntry.path` is therefore always absolute, which the
|
|
40
|
+
* `read_skill_file` sibling reader and the `<skill-location>` anchor both rely
|
|
41
|
+
* on.
|
|
42
|
+
*
|
|
43
|
+
* Mirrors `composeRulesAppend`'s contract for path validation: a configured
|
|
44
|
+
* entry that does not exist or that the harness cannot `stat` rejects
|
|
45
|
+
* `createAgent`, matching the rules-loader behavior so a typo in `config.skills`
|
|
46
|
+
* fails loud at registration time rather than silently dropping the skill at
|
|
47
|
+
* every turn.
|
|
48
|
+
*
|
|
49
|
+
* Skill name resolution: the frontmatter `name:` field wins; if it is missing or
|
|
50
|
+
* empty the parent-folder basename is used. When two configured paths resolve to
|
|
51
|
+
* the same name, **first writer wins** — the second entry is dropped.
|
|
52
|
+
*
|
|
53
|
+
* Frontmatter `description:` is captured verbatim (trimmed) and stored for the
|
|
54
|
+
* `load_skill` tool to surface in its description. When absent, the entry's
|
|
55
|
+
* `description` is the empty string.
|
|
56
|
+
*
|
|
57
|
+
* Frontmatter parsing is intentionally regex-based, not full YAML —
|
|
58
|
+
* `splitFrontmatterAndBody` from `@salesforce/agentic-common` already keeps the
|
|
59
|
+
* parser dependency-free, and the only fields this loader needs are `name` and
|
|
60
|
+
* `description`.
|
|
61
|
+
*
|
|
62
|
+
* A deliberate copy of the Claude harness's `skill-loader.ts`: a cross-harness
|
|
63
|
+
* import is lint-blocked by `harnessIsolationPack`, so the behavior is
|
|
64
|
+
* duplicated on purpose and drift-guarded by the shared
|
|
65
|
+
* `@salesforce/harness-conformance` `SKILL_LOADER_FIXTURES` table (the same
|
|
66
|
+
* posture as `rule-composer.ts` / `mcp-error-classifier.ts`).
|
|
67
|
+
*/
|
|
68
|
+
export declare function buildSkillMap(skillPaths: readonly string[] | undefined, projectRoot: string, logBus?: LogBus): Promise<SkillMap>;
|
|
69
|
+
/**
|
|
70
|
+
* The unique set of skill directories in a {@link SkillMap} — each is the parent
|
|
71
|
+
* directory of a resolved `SKILL.md` (deduplicated, stable order). The
|
|
72
|
+
* `read_skill_file` tool scopes each read to one of these directories so a
|
|
73
|
+
* skill's relative reference (`references/...`, `assets/...`) resolves to a
|
|
74
|
+
* file inside its own skill folder and nothing else on disk is reachable.
|
|
75
|
+
*/
|
|
76
|
+
export declare function skillDirectories(skillMap: SkillMap): string[];
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026, Salesforce, Inc. All rights reserved.
|
|
3
|
+
* See LICENSE.txt for license terms.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'node:fs/promises';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { getErrorMessage, splitFrontmatterAndBody } from '@salesforce/agentic-common';
|
|
8
|
+
const SKILL_FILE_NAME = 'SKILL.md';
|
|
9
|
+
const FRONTMATTER_NAME_RE = /^name:\s*(.+?)\s*$/m;
|
|
10
|
+
const FRONTMATTER_DESCRIPTION_RE = /^description:\s*(.+?)\s*$/m;
|
|
11
|
+
/**
|
|
12
|
+
* Resolve `config.skills` paths into a `Map<skillName, SkillEntry>`. Each entry
|
|
13
|
+
* in `skillPaths` may be:
|
|
14
|
+
*
|
|
15
|
+
* - A `SKILL.md` file path → one skill (named from frontmatter or parent folder
|
|
16
|
+
* basename).
|
|
17
|
+
* - A folder containing `SKILL.md` → one skill.
|
|
18
|
+
* - A parent folder containing one or more skill subfolders, each with its own
|
|
19
|
+
* `SKILL.md` → many skills. Subfolders without a `SKILL.md` are silently
|
|
20
|
+
* skipped so consumers can drop arbitrary subdirectories into their skill
|
|
21
|
+
* roots without breaking the loader.
|
|
22
|
+
*
|
|
23
|
+
* Each entry is resolved against `projectRoot` (via `path.resolve`) before it is
|
|
24
|
+
* `stat`ed, per the SDK `AgentConfig.skills` contract — relative entries resolve
|
|
25
|
+
* against the project root, absolute entries pass through unchanged. The
|
|
26
|
+
* resulting `SkillEntry.path` is therefore always absolute, which the
|
|
27
|
+
* `read_skill_file` sibling reader and the `<skill-location>` anchor both rely
|
|
28
|
+
* on.
|
|
29
|
+
*
|
|
30
|
+
* Mirrors `composeRulesAppend`'s contract for path validation: a configured
|
|
31
|
+
* entry that does not exist or that the harness cannot `stat` rejects
|
|
32
|
+
* `createAgent`, matching the rules-loader behavior so a typo in `config.skills`
|
|
33
|
+
* fails loud at registration time rather than silently dropping the skill at
|
|
34
|
+
* every turn.
|
|
35
|
+
*
|
|
36
|
+
* Skill name resolution: the frontmatter `name:` field wins; if it is missing or
|
|
37
|
+
* empty the parent-folder basename is used. When two configured paths resolve to
|
|
38
|
+
* the same name, **first writer wins** — the second entry is dropped.
|
|
39
|
+
*
|
|
40
|
+
* Frontmatter `description:` is captured verbatim (trimmed) and stored for the
|
|
41
|
+
* `load_skill` tool to surface in its description. When absent, the entry's
|
|
42
|
+
* `description` is the empty string.
|
|
43
|
+
*
|
|
44
|
+
* Frontmatter parsing is intentionally regex-based, not full YAML —
|
|
45
|
+
* `splitFrontmatterAndBody` from `@salesforce/agentic-common` already keeps the
|
|
46
|
+
* parser dependency-free, and the only fields this loader needs are `name` and
|
|
47
|
+
* `description`.
|
|
48
|
+
*
|
|
49
|
+
* A deliberate copy of the Claude harness's `skill-loader.ts`: a cross-harness
|
|
50
|
+
* import is lint-blocked by `harnessIsolationPack`, so the behavior is
|
|
51
|
+
* duplicated on purpose and drift-guarded by the shared
|
|
52
|
+
* `@salesforce/harness-conformance` `SKILL_LOADER_FIXTURES` table (the same
|
|
53
|
+
* posture as `rule-composer.ts` / `mcp-error-classifier.ts`).
|
|
54
|
+
*/
|
|
55
|
+
export async function buildSkillMap(skillPaths, projectRoot, logBus) {
|
|
56
|
+
const map = new Map();
|
|
57
|
+
if (!skillPaths || skillPaths.length === 0)
|
|
58
|
+
return map;
|
|
59
|
+
for (const entry of skillPaths) {
|
|
60
|
+
// Resolve relative entries against the project root per the SDK
|
|
61
|
+
// `AgentConfig.skills` contract; an absolute entry is returned unchanged.
|
|
62
|
+
// This is what makes `SkillEntry.path` (and therefore the sibling-file
|
|
63
|
+
// reader + the `<skill-location>` anchor) absolute, as their contracts
|
|
64
|
+
// require — without it a relative entry would resolve against the host
|
|
65
|
+
// process cwd, which is not the project root.
|
|
66
|
+
const resolved = path.resolve(projectRoot, entry);
|
|
67
|
+
let stats;
|
|
68
|
+
try {
|
|
69
|
+
stats = await fs.stat(resolved);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
throw new Error(`Failed to load skills from "${entry}": ${getErrorMessage(err)}`, { cause: err });
|
|
73
|
+
}
|
|
74
|
+
if (stats.isFile()) {
|
|
75
|
+
if (path.basename(resolved) !== SKILL_FILE_NAME)
|
|
76
|
+
continue;
|
|
77
|
+
await ingestSkillFile(resolved, map, logBus);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!stats.isDirectory())
|
|
81
|
+
continue;
|
|
82
|
+
// Single-skill folder containing SKILL.md?
|
|
83
|
+
const candidate = path.join(resolved, SKILL_FILE_NAME);
|
|
84
|
+
if (await isFile(candidate)) {
|
|
85
|
+
await ingestSkillFile(candidate, map, logBus);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Parent folder: enumerate immediate subdirectories.
|
|
89
|
+
let children;
|
|
90
|
+
try {
|
|
91
|
+
children = await fs.readdir(resolved, { withFileTypes: true });
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
throw new Error(`Failed to load skills from "${entry}": ${getErrorMessage(err)}`, { cause: err });
|
|
95
|
+
}
|
|
96
|
+
for (const child of children) {
|
|
97
|
+
if (!child.isDirectory())
|
|
98
|
+
continue;
|
|
99
|
+
const childSkillMd = path.join(resolved, child.name, SKILL_FILE_NAME);
|
|
100
|
+
if (!(await isFile(childSkillMd)))
|
|
101
|
+
continue;
|
|
102
|
+
await ingestSkillFile(childSkillMd, map, logBus);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return map;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The unique set of skill directories in a {@link SkillMap} — each is the parent
|
|
109
|
+
* directory of a resolved `SKILL.md` (deduplicated, stable order). The
|
|
110
|
+
* `read_skill_file` tool scopes each read to one of these directories so a
|
|
111
|
+
* skill's relative reference (`references/...`, `assets/...`) resolves to a
|
|
112
|
+
* file inside its own skill folder and nothing else on disk is reachable.
|
|
113
|
+
*/
|
|
114
|
+
export function skillDirectories(skillMap) {
|
|
115
|
+
const dirs = new Set();
|
|
116
|
+
for (const entry of skillMap.values()) {
|
|
117
|
+
dirs.add(path.dirname(entry.path));
|
|
118
|
+
}
|
|
119
|
+
return [...dirs];
|
|
120
|
+
}
|
|
121
|
+
async function ingestSkillFile(skillMdPath, map, logBus) {
|
|
122
|
+
let raw;
|
|
123
|
+
try {
|
|
124
|
+
raw = await fs.readFile(skillMdPath, 'utf8');
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
throw new Error(`Failed to read skill file "${skillMdPath}": ${getErrorMessage(err)}`, { cause: err });
|
|
128
|
+
}
|
|
129
|
+
const { frontmatter } = splitFrontmatterAndBody(raw);
|
|
130
|
+
const fm = frontmatter ?? '';
|
|
131
|
+
const name = readField(fm, FRONTMATTER_NAME_RE) ?? path.basename(path.dirname(skillMdPath));
|
|
132
|
+
const description = readField(fm, FRONTMATTER_DESCRIPTION_RE) ?? '';
|
|
133
|
+
if (!name)
|
|
134
|
+
return;
|
|
135
|
+
if (map.has(name)) {
|
|
136
|
+
// First-writer-wins by design (consumers can layer skill folders), but
|
|
137
|
+
// warn so the silent shadow doesn't burn debugging time.
|
|
138
|
+
const winner = map.get(name);
|
|
139
|
+
logBus?.warn(`Skill name "${name}" already loaded; ignoring duplicate at "${skillMdPath}".`, {
|
|
140
|
+
skillName: name,
|
|
141
|
+
keptPath: winner.path,
|
|
142
|
+
ignoredPath: skillMdPath,
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
map.set(name, { path: skillMdPath, description });
|
|
147
|
+
}
|
|
148
|
+
function readField(frontmatter, re) {
|
|
149
|
+
const match = re.exec(frontmatter);
|
|
150
|
+
if (!match?.[1])
|
|
151
|
+
return undefined;
|
|
152
|
+
const trimmed = match[1].trim();
|
|
153
|
+
if (trimmed.length === 0)
|
|
154
|
+
return undefined;
|
|
155
|
+
// Strip a single matched pair of YAML scalar quotes (`"..."` or `'...'`).
|
|
156
|
+
// YAML allows quoting frontmatter scalars to escape colons, leading
|
|
157
|
+
// whitespace, etc. A regex-based reader (kept for the no-YAML-runtime
|
|
158
|
+
// stance) would otherwise capture the quotes verbatim — the resulting
|
|
159
|
+
// `name:` key would include them and the model's `load_skill({ skill })`
|
|
160
|
+
// call would miss the catalog entry. Keeps the cross-harness contract on the
|
|
161
|
+
// same observable shape as Mastra's full YAML parser.
|
|
162
|
+
if (trimmed.length >= 2) {
|
|
163
|
+
const first = trimmed.charAt(0);
|
|
164
|
+
const last = trimmed.charAt(trimmed.length - 1);
|
|
165
|
+
if ((first === '"' || first === "'") && first === last) {
|
|
166
|
+
return trimmed.slice(1, -1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return trimmed;
|
|
170
|
+
}
|
|
171
|
+
async function isFile(p) {
|
|
172
|
+
try {
|
|
173
|
+
const s = await fs.stat(p);
|
|
174
|
+
return s.isFile();
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=skill-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-loader.js","sourceRoot":"","sources":["../src/skill-loader.ts"],"names":[],"mappings":"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"}
|