@xenos1996/usa 2.4.0 → 2.5.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 +2 -2
- package/dist/agent/index.d.ts +9 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/providers.d.ts +56 -0
- package/dist/agent/providers.d.ts.map +1 -0
- package/dist/agent/providers.js +334 -0
- package/dist/agent/providers.js.map +1 -0
- package/dist/agent/types.d.ts +103 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +19 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +31 -0
- package/dist/cli.js.map +1 -1
- package/dist/engine/categories.d.ts +45 -0
- package/dist/engine/categories.d.ts.map +1 -0
- package/dist/engine/categories.js +148 -0
- package/dist/engine/categories.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/rules/categories.yaml +124 -0
- package/rules/core/testing-assurance.yaml +240 -0
- package/rules/index.yaml +1 -0
package/README.md
CHANGED
|
@@ -179,7 +179,7 @@ Override it: `usa audit . --profile production` — the "what would it take to s
|
|
|
179
179
|
|
|
180
180
|
**<!-- usa:fact sections -->16<!-- /usa:fact --> sections**, S1–S16, in [`USA.md`](USA.md) — the human/agent-facing document.
|
|
181
181
|
|
|
182
|
-
**<!-- usa:fact rules-floor -->
|
|
182
|
+
**<!-- usa:fact rules-floor -->310+<!-- /usa:fact --> rules** in [`rules/`](rules) — the machine-facing ones:
|
|
183
183
|
|
|
184
184
|
<!-- usa:begin rules-tree -->
|
|
185
185
|
|
|
@@ -188,7 +188,7 @@ rules/
|
|
|
188
188
|
├── index.yaml pack registry
|
|
189
189
|
├── detectors.yaml ~230 detection signals → facts
|
|
190
190
|
├── profiles/maturity.yaml the five lifecycle profiles
|
|
191
|
-
├── core/
|
|
191
|
+
├── core/ 15 universal packs
|
|
192
192
|
│ ├── repo.yaml ├── security.yaml ├── supply-chain.yaml
|
|
193
193
|
│ ├── architecture.yaml ├── code-quality.yaml ├── testing.yaml
|
|
194
194
|
│ ├── cicd.yaml ├── release.yaml ├── dependencies.yaml
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider layer (outside the deterministic spine: proposes, never decides).
|
|
3
|
+
*
|
|
4
|
+
* IMPLEMENTED: OpenAI-compatible Chat Completions over fetch.
|
|
5
|
+
* PROPOSED (not implemented): Anthropic/Google-native protocols.
|
|
6
|
+
*/
|
|
7
|
+
export type { ChatMessage, ChatRequest, ChatResult, ChatUsage, ModelInfo, ProviderOverrides, ProviderPreset, ReasoningEffort, ResolvedConfig, } from './types.js';
|
|
8
|
+
export { ERROR_SNIPPET_LEN, PROVIDER_PRESETS, REQUEST_TIMEOUT_MS, complete, listModels, loadProviderConfig, } from './providers.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,YAAY,EACV,WAAW,EACX,WAAW,EACX,UAAU,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider layer — one transport: OpenAI-compatible Chat Completions
|
|
3
|
+
* over `fetch`.
|
|
4
|
+
*
|
|
5
|
+
* Covers OpenAI, DeepSeek, Groq, Mistral, Together, OpenRouter, Ollama,
|
|
6
|
+
* LM Studio, vLLM, and custom endpoints — all of which speak
|
|
7
|
+
* `POST {baseURL}/chat/completions` and (hosted ones plus most local ones)
|
|
8
|
+
* `GET {baseURL}/models`.
|
|
9
|
+
*
|
|
10
|
+
* IMPLEMENTED: OpenAI-compatible Chat Completions (`complete`) and model
|
|
11
|
+
* listing (`listModels`) as described above.
|
|
12
|
+
* PROPOSED (not implemented — do not assume they work):
|
|
13
|
+
* - Anthropic-native Messages API transport (distinct auth headers,
|
|
14
|
+
* `anthropic-version`, prompt-caching blocks, thinking blocks).
|
|
15
|
+
* - Google Gemini-native `generateContent` transport (distinct URL shape,
|
|
16
|
+
* `x-goog-api-key`, distinct response envelope and safety metadata).
|
|
17
|
+
* Honesty discipline: only the OpenAI-compatible transport exists. Any
|
|
18
|
+
* caller asking for `anthropic` / `google-native` must fail loudly with
|
|
19
|
+
* "not implemented", never silently emulate.
|
|
20
|
+
*
|
|
21
|
+
* Security rules enforced here:
|
|
22
|
+
* - API keys come ONLY from environment variables. Never from files,
|
|
23
|
+
* CLI args, or defaults. A missing key throws naming the variable
|
|
24
|
+
* (fail-closed); the caller disables LLM features on that error.
|
|
25
|
+
* - Key material is NEVER logged. Tests assert the `Authorization`
|
|
26
|
+
* header shape with a fake key, never a real one.
|
|
27
|
+
*/
|
|
28
|
+
import type { ChatRequest, ChatResult, ModelInfo, ProviderOverrides, ProviderPreset, ResolvedConfig } from './types.js';
|
|
29
|
+
/** Request timeout: 60s per attempt, enforced via `AbortSignal.timeout`. */
|
|
30
|
+
export declare const REQUEST_TIMEOUT_MS = 60000;
|
|
31
|
+
/** Max characters of an error body included in thrown HTTP errors. */
|
|
32
|
+
export declare const ERROR_SNIPPET_LEN = 200;
|
|
33
|
+
export declare const PROVIDER_PRESETS: Record<string, ProviderPreset>;
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a provider id to a concrete config, reading the API key from
|
|
36
|
+
* the environment. Fail-closed: a missing key throws naming the variable;
|
|
37
|
+
* the caller disables LLM features on that error. Never logs key material.
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadProviderConfig(providerId: string, overrides?: ProviderOverrides): ResolvedConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Run one OpenAI-compatible Chat Completions request. Optional fields
|
|
42
|
+
* (`temperature`, `max_tokens`, `reasoning_effort`) are sent ONLY when set,
|
|
43
|
+
* so provider defaults apply otherwise. Non-2xx responses throw an `Error`
|
|
44
|
+
* carrying the HTTP status plus a body snippet (never key material).
|
|
45
|
+
*/
|
|
46
|
+
export declare function complete(req: ChatRequest): Promise<ChatResult>;
|
|
47
|
+
/**
|
|
48
|
+
* List models via `GET {baseURL}/models` (OpenAI shape `{data:[{id}]}` or
|
|
49
|
+
* tolerant variants). Degraded-never-empty: any fetch/HTTP/parse failure
|
|
50
|
+
* falls back to the preset's static default model. If the preset has no
|
|
51
|
+
* static default (custom without a caller-supplied model... which is
|
|
52
|
+
* rejected earlier) and the fetch fails, the error is rethrown loudly —
|
|
53
|
+
* never an empty guess.
|
|
54
|
+
*/
|
|
55
|
+
export declare function listModels(providerId: string, overrides?: ProviderOverrides): Promise<ModelInfo[]>;
|
|
56
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/agent/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAkF3D,CAAC;AAuBF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,iBAAiB,GAC5B,cAAc,CAmBhB;AAgED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAUpE;AAoFD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,iBAAiB,GAC5B,OAAO,CAAC,SAAS,EAAE,CAAC,CAsBtB"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider layer — one transport: OpenAI-compatible Chat Completions
|
|
3
|
+
* over `fetch`.
|
|
4
|
+
*
|
|
5
|
+
* Covers OpenAI, DeepSeek, Groq, Mistral, Together, OpenRouter, Ollama,
|
|
6
|
+
* LM Studio, vLLM, and custom endpoints — all of which speak
|
|
7
|
+
* `POST {baseURL}/chat/completions` and (hosted ones plus most local ones)
|
|
8
|
+
* `GET {baseURL}/models`.
|
|
9
|
+
*
|
|
10
|
+
* IMPLEMENTED: OpenAI-compatible Chat Completions (`complete`) and model
|
|
11
|
+
* listing (`listModels`) as described above.
|
|
12
|
+
* PROPOSED (not implemented — do not assume they work):
|
|
13
|
+
* - Anthropic-native Messages API transport (distinct auth headers,
|
|
14
|
+
* `anthropic-version`, prompt-caching blocks, thinking blocks).
|
|
15
|
+
* - Google Gemini-native `generateContent` transport (distinct URL shape,
|
|
16
|
+
* `x-goog-api-key`, distinct response envelope and safety metadata).
|
|
17
|
+
* Honesty discipline: only the OpenAI-compatible transport exists. Any
|
|
18
|
+
* caller asking for `anthropic` / `google-native` must fail loudly with
|
|
19
|
+
* "not implemented", never silently emulate.
|
|
20
|
+
*
|
|
21
|
+
* Security rules enforced here:
|
|
22
|
+
* - API keys come ONLY from environment variables. Never from files,
|
|
23
|
+
* CLI args, or defaults. A missing key throws naming the variable
|
|
24
|
+
* (fail-closed); the caller disables LLM features on that error.
|
|
25
|
+
* - Key material is NEVER logged. Tests assert the `Authorization`
|
|
26
|
+
* header shape with a fake key, never a real one.
|
|
27
|
+
*/
|
|
28
|
+
/** Request timeout: 60s per attempt, enforced via `AbortSignal.timeout`. */
|
|
29
|
+
export const REQUEST_TIMEOUT_MS = 60_000;
|
|
30
|
+
/** Max characters of an error body included in thrown HTTP errors. */
|
|
31
|
+
export const ERROR_SNIPPET_LEN = 200;
|
|
32
|
+
export const PROVIDER_PRESETS = {
|
|
33
|
+
openai: {
|
|
34
|
+
id: 'openai',
|
|
35
|
+
label: 'OpenAI',
|
|
36
|
+
baseURL: 'https://api.openai.com/v1',
|
|
37
|
+
apiKeyEnv: 'OPENAI_API_KEY',
|
|
38
|
+
defaultModel: 'gpt-4o-mini',
|
|
39
|
+
fetchModels: true,
|
|
40
|
+
},
|
|
41
|
+
deepseek: {
|
|
42
|
+
id: 'deepseek',
|
|
43
|
+
label: 'DeepSeek',
|
|
44
|
+
baseURL: 'https://api.deepseek.com/v1',
|
|
45
|
+
apiKeyEnv: 'DEEPSEEK_API_KEY',
|
|
46
|
+
defaultModel: 'deepseek-chat',
|
|
47
|
+
fetchModels: true,
|
|
48
|
+
},
|
|
49
|
+
groq: {
|
|
50
|
+
id: 'groq',
|
|
51
|
+
label: 'Groq',
|
|
52
|
+
baseURL: 'https://api.groq.com/openai/v1',
|
|
53
|
+
apiKeyEnv: 'GROQ_API_KEY',
|
|
54
|
+
defaultModel: 'llama-3.3-70b-versatile',
|
|
55
|
+
freeTier: true,
|
|
56
|
+
fetchModels: true,
|
|
57
|
+
},
|
|
58
|
+
mistral: {
|
|
59
|
+
id: 'mistral',
|
|
60
|
+
label: 'Mistral',
|
|
61
|
+
baseURL: 'https://api.mistral.ai/v1',
|
|
62
|
+
apiKeyEnv: 'MISTRAL_API_KEY',
|
|
63
|
+
defaultModel: 'mistral-small-latest',
|
|
64
|
+
freeTier: true,
|
|
65
|
+
fetchModels: true,
|
|
66
|
+
},
|
|
67
|
+
together: {
|
|
68
|
+
id: 'together',
|
|
69
|
+
label: 'Together AI',
|
|
70
|
+
baseURL: 'https://api.together.xyz/v1',
|
|
71
|
+
apiKeyEnv: 'TOGETHER_API_KEY',
|
|
72
|
+
defaultModel: 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo',
|
|
73
|
+
fetchModels: true,
|
|
74
|
+
},
|
|
75
|
+
openrouter: {
|
|
76
|
+
id: 'openrouter',
|
|
77
|
+
label: 'OpenRouter',
|
|
78
|
+
baseURL: 'https://openrouter.ai/api/v1',
|
|
79
|
+
apiKeyEnv: 'OPENROUTER_API_KEY',
|
|
80
|
+
defaultModel: 'openai/gpt-4o-mini',
|
|
81
|
+
freeTier: true,
|
|
82
|
+
fetchModels: true,
|
|
83
|
+
},
|
|
84
|
+
ollama: {
|
|
85
|
+
id: 'ollama',
|
|
86
|
+
label: 'Ollama (local)',
|
|
87
|
+
baseURL: 'http://localhost:11434/v1',
|
|
88
|
+
apiKeyEnv: '',
|
|
89
|
+
defaultModel: 'llama3.1',
|
|
90
|
+
freeTier: true,
|
|
91
|
+
fetchModels: true,
|
|
92
|
+
},
|
|
93
|
+
lmstudio: {
|
|
94
|
+
id: 'lmstudio',
|
|
95
|
+
label: 'LM Studio (local)',
|
|
96
|
+
baseURL: 'http://localhost:1234/v1',
|
|
97
|
+
apiKeyEnv: '',
|
|
98
|
+
defaultModel: 'local-model',
|
|
99
|
+
freeTier: true,
|
|
100
|
+
fetchModels: true,
|
|
101
|
+
},
|
|
102
|
+
custom: {
|
|
103
|
+
id: 'custom',
|
|
104
|
+
label: 'Custom OpenAI-compatible endpoint',
|
|
105
|
+
// Empty on purpose: the caller MUST supply baseURL (and usually
|
|
106
|
+
// apiKeyEnv/model) via overrides. Any vLLM / text-generation-webui /
|
|
107
|
+
// corporate-gateway endpoint works as long as it speaks the
|
|
108
|
+
// OpenAI-compatible Chat Completions dialect.
|
|
109
|
+
baseURL: '',
|
|
110
|
+
apiKeyEnv: '',
|
|
111
|
+
defaultModel: '',
|
|
112
|
+
fetchModels: false,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
/** Names of explicitly PROPOSED-but-unimplemented native transports. */
|
|
116
|
+
const UNIMPLEMENTED_TRANSPORTS = new Set(['anthropic', 'google', 'gemini', 'vertex', 'bedrock']);
|
|
117
|
+
/** Resolve a provider id to its preset, or throw naming what exists. */
|
|
118
|
+
function findPreset(providerId) {
|
|
119
|
+
if (UNIMPLEMENTED_TRANSPORTS.has(providerId)) {
|
|
120
|
+
throw new Error(`LLM provider "${providerId}" is PROPOSED, not implemented: ` +
|
|
121
|
+
`only OpenAI-compatible Chat Completions transports are available ` +
|
|
122
|
+
`(${Object.keys(PROVIDER_PRESETS).join(', ')}).`);
|
|
123
|
+
}
|
|
124
|
+
const preset = PROVIDER_PRESETS[providerId];
|
|
125
|
+
if (!preset) {
|
|
126
|
+
throw new Error(`Unknown LLM provider "${providerId}". Known providers: ${Object.keys(PROVIDER_PRESETS).join(', ')}.`);
|
|
127
|
+
}
|
|
128
|
+
return preset;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Resolve a provider id to a concrete config, reading the API key from
|
|
132
|
+
* the environment. Fail-closed: a missing key throws naming the variable;
|
|
133
|
+
* the caller disables LLM features on that error. Never logs key material.
|
|
134
|
+
*/
|
|
135
|
+
export function loadProviderConfig(providerId, overrides) {
|
|
136
|
+
const preset = findPreset(providerId);
|
|
137
|
+
const baseURL = overrides?.baseURL ?? preset.baseURL;
|
|
138
|
+
if (!baseURL) {
|
|
139
|
+
throw new Error(`LLM provider "${providerId}" has no baseURL: supply one via overrides.baseURL ` +
|
|
140
|
+
`(custom endpoints must always provide a baseURL).`);
|
|
141
|
+
}
|
|
142
|
+
const apiKey = resolveApiKey(providerId, overrides?.apiKeyEnv ?? preset.apiKeyEnv);
|
|
143
|
+
const model = resolveModel(providerId, overrides?.model ?? preset.defaultModel);
|
|
144
|
+
const resolved = {
|
|
145
|
+
providerId: preset.id,
|
|
146
|
+
label: preset.label,
|
|
147
|
+
baseURL: stripTrailingSlashes(baseURL),
|
|
148
|
+
model,
|
|
149
|
+
};
|
|
150
|
+
if (apiKey !== undefined)
|
|
151
|
+
resolved.apiKey = apiKey;
|
|
152
|
+
return resolved;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Trailing-slash strip without a regex: the input is caller-controlled
|
|
156
|
+
* (custom baseURL), and a regex here is a ReDoS surface CodeQL flags.
|
|
157
|
+
* Linear scan, identical result to `/\/+$/` removal.
|
|
158
|
+
*/
|
|
159
|
+
function stripTrailingSlashes(url) {
|
|
160
|
+
let end = url.length;
|
|
161
|
+
while (end > 0 && url[end - 1] === '/')
|
|
162
|
+
end -= 1;
|
|
163
|
+
return url.slice(0, end);
|
|
164
|
+
}
|
|
165
|
+
/** Key from the environment, or undefined for keyless local endpoints. */
|
|
166
|
+
function resolveApiKey(providerId, apiKeyEnv) {
|
|
167
|
+
if (!apiKeyEnv)
|
|
168
|
+
return undefined;
|
|
169
|
+
const raw = process.env[apiKeyEnv];
|
|
170
|
+
if (!raw) {
|
|
171
|
+
throw new Error(`LLM provider "${providerId}" needs an API key: environment variable ${apiKeyEnv} ` +
|
|
172
|
+
`is missing or empty. Set it, or disable LLM features.`);
|
|
173
|
+
}
|
|
174
|
+
return raw;
|
|
175
|
+
}
|
|
176
|
+
/** Explicit model wins; otherwise the preset default (both may be absent). */
|
|
177
|
+
function resolveModel(providerId, model) {
|
|
178
|
+
if (model)
|
|
179
|
+
return model;
|
|
180
|
+
throw new Error(`LLM provider "${providerId}" has no default model: supply one via overrides.model ` +
|
|
181
|
+
`or ChatRequest.model.`);
|
|
182
|
+
}
|
|
183
|
+
function authHeaders(apiKey) {
|
|
184
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
185
|
+
if (apiKey !== undefined)
|
|
186
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
187
|
+
return headers;
|
|
188
|
+
}
|
|
189
|
+
async function readSnippet(res) {
|
|
190
|
+
try {
|
|
191
|
+
return (await res.text()).slice(0, ERROR_SNIPPET_LEN);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return '<unreadable body>';
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function numOrUndefined(v) {
|
|
198
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Run one OpenAI-compatible Chat Completions request. Optional fields
|
|
202
|
+
* (`temperature`, `max_tokens`, `reasoning_effort`) are sent ONLY when set,
|
|
203
|
+
* so provider defaults apply otherwise. Non-2xx responses throw an `Error`
|
|
204
|
+
* carrying the HTTP status plus a body snippet (never key material).
|
|
205
|
+
*/
|
|
206
|
+
export async function complete(req) {
|
|
207
|
+
const cfg = loadProviderConfig(req.provider, { model: req.model });
|
|
208
|
+
const res = await fetch(`${cfg.baseURL}/chat/completions`, {
|
|
209
|
+
method: 'POST',
|
|
210
|
+
headers: authHeaders(cfg.apiKey),
|
|
211
|
+
body: JSON.stringify(buildChatBody(req, cfg.model)),
|
|
212
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
213
|
+
});
|
|
214
|
+
await ensureOk(res);
|
|
215
|
+
return readChatResult(res, cfg.model);
|
|
216
|
+
}
|
|
217
|
+
/** Optional fields ride along ONLY when set — provider defaults win otherwise. */
|
|
218
|
+
function buildChatBody(req, model) {
|
|
219
|
+
const body = {
|
|
220
|
+
model,
|
|
221
|
+
messages: req.messages.map((m) => ({ role: m.role, content: m.content })),
|
|
222
|
+
};
|
|
223
|
+
if (req.temperature !== undefined)
|
|
224
|
+
body['temperature'] = req.temperature;
|
|
225
|
+
if (req.maxTokens !== undefined)
|
|
226
|
+
body['max_tokens'] = req.maxTokens;
|
|
227
|
+
if (req.reasoningEffort !== undefined)
|
|
228
|
+
body['reasoning_effort'] = req.reasoningEffort;
|
|
229
|
+
return body;
|
|
230
|
+
}
|
|
231
|
+
/** Non-2xx becomes an Error carrying status plus a body snippet (no keys). */
|
|
232
|
+
async function ensureOk(res) {
|
|
233
|
+
if (res.ok)
|
|
234
|
+
return;
|
|
235
|
+
const snippet = await readSnippet(res);
|
|
236
|
+
throw new Error(`Chat completions request failed: HTTP ${res.status} ${snippet}`);
|
|
237
|
+
}
|
|
238
|
+
/** Parse the completion envelope; anything shapeless throws loudly. */
|
|
239
|
+
async function readChatResult(res, fallbackModel) {
|
|
240
|
+
let json;
|
|
241
|
+
try {
|
|
242
|
+
json = (await res.json());
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
throw new Error(`Chat completions request failed: unreadable JSON response (${err.message})`, {
|
|
246
|
+
cause: err,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
const content = json.choices?.[0]?.message?.content;
|
|
250
|
+
if (typeof content !== 'string') {
|
|
251
|
+
throw new Error('Chat completions request failed: response has no choices[0].message.content string');
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
text: content,
|
|
255
|
+
model: typeof json.model === 'string' && json.model ? json.model : fallbackModel,
|
|
256
|
+
...usageOf(json),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/** Usage block only when at least one counter parsed (else omitted). */
|
|
260
|
+
function usageOf(json) {
|
|
261
|
+
const promptTokens = numOrUndefined(json.usage?.prompt_tokens);
|
|
262
|
+
const completionTokens = numOrUndefined(json.usage?.completion_tokens);
|
|
263
|
+
const totalTokens = numOrUndefined(json.usage?.total_tokens);
|
|
264
|
+
if (promptTokens === undefined && completionTokens === undefined && totalTokens === undefined) {
|
|
265
|
+
return {};
|
|
266
|
+
}
|
|
267
|
+
const usage = {};
|
|
268
|
+
if (promptTokens !== undefined)
|
|
269
|
+
usage.promptTokens = promptTokens;
|
|
270
|
+
if (completionTokens !== undefined)
|
|
271
|
+
usage.completionTokens = completionTokens;
|
|
272
|
+
if (totalTokens !== undefined)
|
|
273
|
+
usage.totalTokens = totalTokens;
|
|
274
|
+
return { usage };
|
|
275
|
+
}
|
|
276
|
+
/** Extract model names tolerantly from a `GET /models` payload. */
|
|
277
|
+
function parseModelList(json) {
|
|
278
|
+
const names = [];
|
|
279
|
+
const push = (v) => {
|
|
280
|
+
if (typeof v === 'string' && v)
|
|
281
|
+
names.push(v);
|
|
282
|
+
else if (v && typeof v === 'object') {
|
|
283
|
+
const o = v;
|
|
284
|
+
const cand = o['name'] ?? o['id'];
|
|
285
|
+
if (typeof cand === 'string' && cand)
|
|
286
|
+
names.push(cand);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
if (Array.isArray(json)) {
|
|
290
|
+
for (const item of json)
|
|
291
|
+
push(item);
|
|
292
|
+
}
|
|
293
|
+
else if (json && typeof json === 'object') {
|
|
294
|
+
const data = json['data'];
|
|
295
|
+
if (Array.isArray(data)) {
|
|
296
|
+
for (const item of data)
|
|
297
|
+
push(item);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return [...new Set(names)];
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* List models via `GET {baseURL}/models` (OpenAI shape `{data:[{id}]}` or
|
|
304
|
+
* tolerant variants). Degraded-never-empty: any fetch/HTTP/parse failure
|
|
305
|
+
* falls back to the preset's static default model. If the preset has no
|
|
306
|
+
* static default (custom without a caller-supplied model... which is
|
|
307
|
+
* rejected earlier) and the fetch fails, the error is rethrown loudly —
|
|
308
|
+
* never an empty guess.
|
|
309
|
+
*/
|
|
310
|
+
export async function listModels(providerId, overrides) {
|
|
311
|
+
const cfg = loadProviderConfig(providerId, overrides);
|
|
312
|
+
try {
|
|
313
|
+
const res = await fetch(`${cfg.baseURL}/models`, {
|
|
314
|
+
method: 'GET',
|
|
315
|
+
headers: authHeaders(cfg.apiKey),
|
|
316
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
317
|
+
});
|
|
318
|
+
if (!res.ok)
|
|
319
|
+
throw new Error(`HTTP ${res.status}`);
|
|
320
|
+
const json = await res.json();
|
|
321
|
+
const names = parseModelList(json);
|
|
322
|
+
if (names.length === 0)
|
|
323
|
+
throw new Error('empty model list');
|
|
324
|
+
return names.map((name) => ({ name }));
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
if (!cfg.model) {
|
|
328
|
+
throw new Error(`Could not list models for provider "${providerId}" and no static default exists: ` +
|
|
329
|
+
`supply overrides.model.`);
|
|
330
|
+
}
|
|
331
|
+
return [{ name: cfg.model }];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/agent/providers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider layer — shared request/result types.
|
|
3
|
+
*
|
|
4
|
+
* Doctrine: the deterministic offline spine never depends on this layer.
|
|
5
|
+
* The LLM only *proposes* from outside the spine; the engine verifies.
|
|
6
|
+
* Every key comes from the environment (fail-closed when missing); key
|
|
7
|
+
* material is never logged.
|
|
8
|
+
*
|
|
9
|
+
* IMPLEMENTED: OpenAI-compatible Chat Completions over `fetch`.
|
|
10
|
+
* PROPOSED (not implemented — do not assume they work):
|
|
11
|
+
* - Anthropic Messages API (`anthropic-*` headers, `anthropic-version`):
|
|
12
|
+
* different auth scheme, prompt-caching headers, and message roles.
|
|
13
|
+
* - Google Gemini native `generateContent` protocol (`:generateContent`,
|
|
14
|
+
* `x-goog-api-key`): different URL shape and response envelope.
|
|
15
|
+
* Both remain documented follow-ups until a contributor adds a dedicated
|
|
16
|
+
* transport plus tests. Anything not listed under IMPLEMENTED does not work.
|
|
17
|
+
*/
|
|
18
|
+
/** A single turn in a chat-completions conversation. */
|
|
19
|
+
export interface ChatMessage {
|
|
20
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
21
|
+
content: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Reasoning-effort hint forwarded verbatim as `reasoning_effort`.
|
|
25
|
+
* Kept as a plain string: the accepted values differ per vendor
|
|
26
|
+
* (OpenAI `low|medium|high`, others accept `minimal`, `xhigh`, …),
|
|
27
|
+
* so this layer does not validate — the server decides.
|
|
28
|
+
*/
|
|
29
|
+
export type ReasoningEffort = string;
|
|
30
|
+
/** One LLM completion request against a configured provider preset. */
|
|
31
|
+
export interface ChatRequest {
|
|
32
|
+
/** Key of {@link PROVIDER_PRESETS} (see providers.ts). */
|
|
33
|
+
provider: string;
|
|
34
|
+
/** Model id as advertised by the provider (e.g. `gpt-4o-mini`). */
|
|
35
|
+
model: string;
|
|
36
|
+
messages: ChatMessage[];
|
|
37
|
+
temperature?: number;
|
|
38
|
+
maxTokens?: number;
|
|
39
|
+
reasoningEffort?: ReasoningEffort;
|
|
40
|
+
}
|
|
41
|
+
/** Token usage reported by the provider, when it reports any. */
|
|
42
|
+
export interface ChatUsage {
|
|
43
|
+
promptTokens?: number;
|
|
44
|
+
completionTokens?: number;
|
|
45
|
+
totalTokens?: number;
|
|
46
|
+
}
|
|
47
|
+
/** The assistant's reply plus echo of the serving model. */
|
|
48
|
+
export interface ChatResult {
|
|
49
|
+
text: string;
|
|
50
|
+
model: string;
|
|
51
|
+
usage?: ChatUsage;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Static description of one OpenAI-compatible endpoint.
|
|
55
|
+
* `baseURL` is the API root WITHOUT a trailing path operation
|
|
56
|
+
* (this layer appends `/chat/completions` and `/models`).
|
|
57
|
+
*/
|
|
58
|
+
export interface ProviderPreset {
|
|
59
|
+
/** Stable key used in {@link ChatRequest.provider}. */
|
|
60
|
+
id: string;
|
|
61
|
+
/** Human-readable label for status/CLI output. */
|
|
62
|
+
label: string;
|
|
63
|
+
/** API root, e.g. `https://api.openai.com/v1`. */
|
|
64
|
+
baseURL: string;
|
|
65
|
+
/**
|
|
66
|
+
* Environment variable holding the API key. Empty string means the
|
|
67
|
+
* provider needs no key (local runtimes); such presets never throw
|
|
68
|
+
* for a missing key and send no `Authorization` header.
|
|
69
|
+
*/
|
|
70
|
+
apiKeyEnv: string;
|
|
71
|
+
/**
|
|
72
|
+
* Model used when the caller does not pick one. Empty string means
|
|
73
|
+
* "no static default" — the caller MUST supply a model and a failed
|
|
74
|
+
* `/models` fetch throws loudly instead of falling back.
|
|
75
|
+
*/
|
|
76
|
+
defaultModel: string;
|
|
77
|
+
/** Whether the vendor offers a free tier (informational only). */
|
|
78
|
+
freeTier?: boolean;
|
|
79
|
+
/** Whether the vendor is known to serve `GET {baseURL}/models`. */
|
|
80
|
+
fetchModels: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** A model id advertised via (or in place of) `GET {baseURL}/models`. */
|
|
83
|
+
export interface ModelInfo {
|
|
84
|
+
name: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A preset with secrets resolved. `apiKey` is `undefined` exactly when
|
|
88
|
+
* the preset needs no key; it is never read from files or CLI args.
|
|
89
|
+
*/
|
|
90
|
+
export interface ResolvedConfig {
|
|
91
|
+
providerId: string;
|
|
92
|
+
label: string;
|
|
93
|
+
baseURL: string;
|
|
94
|
+
apiKey?: string;
|
|
95
|
+
model: string;
|
|
96
|
+
}
|
|
97
|
+
/** Caller-supplied overrides, used for the `custom` preset. */
|
|
98
|
+
export interface ProviderOverrides {
|
|
99
|
+
baseURL?: string;
|
|
100
|
+
apiKeyEnv?: string;
|
|
101
|
+
model?: string;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,yEAAyE;AACzE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider layer — shared request/result types.
|
|
3
|
+
*
|
|
4
|
+
* Doctrine: the deterministic offline spine never depends on this layer.
|
|
5
|
+
* The LLM only *proposes* from outside the spine; the engine verifies.
|
|
6
|
+
* Every key comes from the environment (fail-closed when missing); key
|
|
7
|
+
* material is never logged.
|
|
8
|
+
*
|
|
9
|
+
* IMPLEMENTED: OpenAI-compatible Chat Completions over `fetch`.
|
|
10
|
+
* PROPOSED (not implemented — do not assume they work):
|
|
11
|
+
* - Anthropic Messages API (`anthropic-*` headers, `anthropic-version`):
|
|
12
|
+
* different auth scheme, prompt-caching headers, and message roles.
|
|
13
|
+
* - Google Gemini native `generateContent` protocol (`:generateContent`,
|
|
14
|
+
* `x-goog-api-key`): different URL shape and response envelope.
|
|
15
|
+
* Both remain documented follow-ups until a contributor adds a dedicated
|
|
16
|
+
* transport plus tests. Anything not listed under IMPLEMENTED does not work.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAoHA,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CA6B3C;AAm3BD,iBAAS,YAAY,CACnB,KAAK,GAAE,MAAM,GAAG,SAA2B,EAC3C,OAAO,GAAE,MAAwB,GAChC,OAAO,CAOT;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import { runEvolutionCycle } from './evolution/run.js';
|
|
|
21
21
|
import { capabilityFromPack } from './evolution/capability.js';
|
|
22
22
|
import { ruleAutomatability } from './engine/automatability.js';
|
|
23
23
|
import { catalogueCoverage, catalogueOf, loadCatalogues } from './engine/catalogues.js';
|
|
24
|
+
import { categoryCoverage, loadCategories } from './engine/categories.js';
|
|
24
25
|
import { runFoundationInit, runFoundationShow } from './foundation/interview.js';
|
|
25
26
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
26
27
|
const DEFAULT_RULES_DIR = path.resolve(HERE, '..', 'rules');
|
|
@@ -85,6 +86,7 @@ const COMMANDS = {
|
|
|
85
86
|
evolve: cmdEvolve,
|
|
86
87
|
standards: cmdStandards,
|
|
87
88
|
foundation: cmdFoundation,
|
|
89
|
+
categories: cmdCategories,
|
|
88
90
|
};
|
|
89
91
|
export function main(argv) {
|
|
90
92
|
const args = parseArgs(argv);
|
|
@@ -365,6 +367,30 @@ function cmdStandards(args) {
|
|
|
365
367
|
}
|
|
366
368
|
return 0;
|
|
367
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Category coverage is derived, never scored (ADR-0030 taxonomy rule): the
|
|
372
|
+
* table answers "which future domains already have rules" without touching
|
|
373
|
+
* scoring, gates, or confidence.
|
|
374
|
+
*/
|
|
375
|
+
function cmdCategories(args) {
|
|
376
|
+
const rulesDir = path.resolve(str(args, 'rules-dir', DEFAULT_RULES_DIR) ?? DEFAULT_RULES_DIR);
|
|
377
|
+
const { packs } = loadRulePacks(rulesDir);
|
|
378
|
+
const { categories, warnings } = loadCategories(rulesDir);
|
|
379
|
+
for (const w of warnings)
|
|
380
|
+
console.error(`warning: ${w}`);
|
|
381
|
+
const rows = categoryCoverage(packs, categories);
|
|
382
|
+
const fmt = (str(args, 'format') ?? 'md').toLowerCase();
|
|
383
|
+
if (fmt === 'json') {
|
|
384
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
385
|
+
return 0;
|
|
386
|
+
}
|
|
387
|
+
console.log('| Category | Rules | Sections |');
|
|
388
|
+
console.log('| -------- | ----- | -------- |');
|
|
389
|
+
for (const row of rows) {
|
|
390
|
+
console.log(`| ${row.name} (\`${row.id}\`) | ${row.ruleCount} | ${row.sections.join(', ') || '—'} |`);
|
|
391
|
+
}
|
|
392
|
+
return 0;
|
|
393
|
+
}
|
|
368
394
|
/* ------------------------------------------------------------ foundation -- */
|
|
369
395
|
function cmdFoundation(args) {
|
|
370
396
|
const sub = args._[1];
|
|
@@ -809,6 +835,7 @@ usa — Universal Software Auditor
|
|
|
809
835
|
usa learn <report.md> Generate suggested rules from audit findings
|
|
810
836
|
usa evolve [path] Run the audit → gap → candidate → release loop
|
|
811
837
|
usa standards Report catalogue coverage and automatability
|
|
838
|
+
usa categories Report future-domain category coverage
|
|
812
839
|
usa foundation init [path] Capture project intent into .usa/foundation.yaml
|
|
813
840
|
usa foundation show [path] Print the effective intent and asserted facts
|
|
814
841
|
|
|
@@ -830,6 +857,10 @@ standards options
|
|
|
830
857
|
--format <fmt> md | json (default md)
|
|
831
858
|
--rules-dir <dir> Rule pack directory (default bundled rules/)
|
|
832
859
|
|
|
860
|
+
categories options
|
|
861
|
+
--format <fmt> md | json (default md)
|
|
862
|
+
--rules-dir <dir> Rule pack directory (default bundled rules/)
|
|
863
|
+
|
|
833
864
|
foundation options
|
|
834
865
|
--dir <path> Project directory (default .; a positional path works too)
|
|
835
866
|
--non-interactive Write the defaults file without prompting (init only)
|