@mrciphersmith/keryx 0.2.49 → 0.2.50
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 +13 -0
- package/dist/cli.js +2093 -420
- package/package.json +1 -1
- package/src/gdgraph/enrich.ts +24 -7
- package/src/gdgraph/treesitter/adapter.test.ts +145 -2
- package/src/gdgraph/treesitter/adapter.ts +85 -1
package/dist/cli.js
CHANGED
|
@@ -186,14 +186,14 @@ var init_config_dir = __esm(() => {
|
|
|
186
186
|
// src/lib/fs.ts
|
|
187
187
|
var exports_fs = {};
|
|
188
188
|
__export(exports_fs, {
|
|
189
|
-
|
|
190
|
-
withFileLock: () => withFileLock2,
|
|
191
|
-
toPosix: () => toPosix,
|
|
192
|
-
pathExists: () => pathExists,
|
|
193
|
-
isPathInside: () => isPathInside,
|
|
194
|
-
isNotFound: () => isNotFound,
|
|
189
|
+
DEFAULT_LOCK_STALE_MS: () => DEFAULT_LOCK_STALE_MS,
|
|
195
190
|
isLockHeld: () => isLockHeld,
|
|
196
|
-
|
|
191
|
+
isNotFound: () => isNotFound,
|
|
192
|
+
isPathInside: () => isPathInside,
|
|
193
|
+
pathExists: () => pathExists,
|
|
194
|
+
toPosix: () => toPosix,
|
|
195
|
+
withFileLock: () => withFileLock2,
|
|
196
|
+
writeFileAtomic: () => writeFileAtomic
|
|
197
197
|
});
|
|
198
198
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
199
199
|
import { access, mkdir, readFile, rename, rm, stat, utimes, writeFile } from "fs/promises";
|
|
@@ -5372,13 +5372,13 @@ var init_service2 = __esm(() => {
|
|
|
5372
5372
|
// src/lib/shell-config.ts
|
|
5373
5373
|
var exports_shell_config = {};
|
|
5374
5374
|
__export(exports_shell_config, {
|
|
5375
|
-
|
|
5376
|
-
saveShellConfig: () => saveShellConfig,
|
|
5377
|
-
saveProviderBaseUrl: () => saveProviderBaseUrl,
|
|
5378
|
-
saveApiKey: () => saveApiKey,
|
|
5379
|
-
loadShellConfig: () => loadShellConfig,
|
|
5375
|
+
applySavedApiKeys: () => applySavedApiKeys,
|
|
5380
5376
|
envWithSavedApiKeys: () => envWithSavedApiKeys,
|
|
5381
|
-
|
|
5377
|
+
loadShellConfig: () => loadShellConfig,
|
|
5378
|
+
saveApiKey: () => saveApiKey,
|
|
5379
|
+
saveProviderBaseUrl: () => saveProviderBaseUrl,
|
|
5380
|
+
saveShellConfig: () => saveShellConfig,
|
|
5381
|
+
shellConfigPath: () => shellConfigPath
|
|
5382
5382
|
});
|
|
5383
5383
|
import { existsSync as existsSync7 } from "fs";
|
|
5384
5384
|
import path35 from "path";
|
|
@@ -5987,6 +5987,40 @@ function createTreesitterSpec(cwd, config) {
|
|
|
5987
5987
|
load: (ctx) => new TreesitterAdapter(cwd, config, ctx.dep)
|
|
5988
5988
|
};
|
|
5989
5989
|
}
|
|
5990
|
+
async function loadTreesitterDepLiteral() {
|
|
5991
|
+
try {
|
|
5992
|
+
return await import("web-tree-sitter");
|
|
5993
|
+
} catch {
|
|
5994
|
+
return;
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
async function resolveTreesitterCapability(cwd, config, resolve = resolveCapability) {
|
|
5998
|
+
const spec = createTreesitterSpec(cwd, config);
|
|
5999
|
+
try {
|
|
6000
|
+
if (!await isCapabilityEnabled(cwd, spec.id)) {
|
|
6001
|
+
return null;
|
|
6002
|
+
}
|
|
6003
|
+
const literalDep = await loadTreesitterDepLiteral();
|
|
6004
|
+
if (literalDep === undefined) {
|
|
6005
|
+
return await resolve(cwd, spec);
|
|
6006
|
+
}
|
|
6007
|
+
const adapter = spec.load({ dep: literalDep, asset: null });
|
|
6008
|
+
let available;
|
|
6009
|
+
try {
|
|
6010
|
+
available = await adapter.isAvailable();
|
|
6011
|
+
} catch {
|
|
6012
|
+
warnCapabilityDegraded(spec.id, "adapter availability check threw");
|
|
6013
|
+
return null;
|
|
6014
|
+
}
|
|
6015
|
+
if (!available) {
|
|
6016
|
+
warnCapabilityDegraded(spec.id, "adapter reported unavailable");
|
|
6017
|
+
return null;
|
|
6018
|
+
}
|
|
6019
|
+
return adapter;
|
|
6020
|
+
} catch {
|
|
6021
|
+
return null;
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
5990
6024
|
|
|
5991
6025
|
class TreesitterAdapter {
|
|
5992
6026
|
cwd;
|
|
@@ -6102,6 +6136,8 @@ function compareCalls2(a, b) {
|
|
|
6102
6136
|
return a.kind < b.kind ? -1 : a.kind > b.kind ? 1 : 0;
|
|
6103
6137
|
}
|
|
6104
6138
|
var init_adapter = __esm(() => {
|
|
6139
|
+
init_seam();
|
|
6140
|
+
init_warn_once();
|
|
6105
6141
|
init_extract();
|
|
6106
6142
|
init_grammars();
|
|
6107
6143
|
});
|
|
@@ -6113,13 +6149,13 @@ __export(exports_enrich, {
|
|
|
6113
6149
|
});
|
|
6114
6150
|
import { mkdir as mkdir18, writeFile as writeFile20 } from "fs/promises";
|
|
6115
6151
|
import path48 from "path";
|
|
6116
|
-
async function enrichBuildWithSymbols(cwd, files, resolve
|
|
6152
|
+
async function enrichBuildWithSymbols(cwd, files, resolve) {
|
|
6117
6153
|
const config = await loadGdgraphConfig(cwd);
|
|
6118
|
-
const
|
|
6154
|
+
const treesitterConfig = {
|
|
6119
6155
|
languages: config.treesitter.languages,
|
|
6120
6156
|
grammarsPath: config.treesitter.grammarsPath
|
|
6121
|
-
}
|
|
6122
|
-
const adapter = await resolve(cwd,
|
|
6157
|
+
};
|
|
6158
|
+
const adapter = resolve ? await resolve(cwd, createTreesitterSpec(cwd, treesitterConfig)) : await resolveTreesitterCapability(cwd, treesitterConfig);
|
|
6123
6159
|
if (!adapter) {
|
|
6124
6160
|
return { enriched: false, symbols: 0, calls: 0 };
|
|
6125
6161
|
}
|
|
@@ -6746,10 +6782,10 @@ var init_target = () => {};
|
|
|
6746
6782
|
// src/gdgraph/query.ts
|
|
6747
6783
|
var exports_query = {};
|
|
6748
6784
|
__export(exports_query, {
|
|
6749
|
-
|
|
6750
|
-
getOrphans: () => getOrphans,
|
|
6785
|
+
getAffected: () => getAffected,
|
|
6751
6786
|
getCycles: () => getCycles,
|
|
6752
|
-
|
|
6787
|
+
getOrphans: () => getOrphans,
|
|
6788
|
+
loadGraph: () => loadGraph
|
|
6753
6789
|
});
|
|
6754
6790
|
import { readFile as readFile24 } from "fs/promises";
|
|
6755
6791
|
import path51 from "path";
|
|
@@ -7388,12 +7424,12 @@ var init_repomap = __esm(() => {
|
|
|
7388
7424
|
// src/sync/provenance.ts
|
|
7389
7425
|
var exports_provenance = {};
|
|
7390
7426
|
__export(exports_provenance, {
|
|
7391
|
-
|
|
7392
|
-
readProvenance: () => readProvenance,
|
|
7393
|
-
provenancePath: () => provenancePath,
|
|
7394
|
-
gitHead: () => gitHead,
|
|
7427
|
+
SYNCED_MODULES: () => SYNCED_MODULES,
|
|
7395
7428
|
gitCmd: () => gitCmd,
|
|
7396
|
-
|
|
7429
|
+
gitHead: () => gitHead,
|
|
7430
|
+
provenancePath: () => provenancePath,
|
|
7431
|
+
readProvenance: () => readProvenance,
|
|
7432
|
+
recordProvenance: () => recordProvenance
|
|
7397
7433
|
});
|
|
7398
7434
|
import { mkdir as mkdir21, readFile as readFile25, writeFile as writeFile23 } from "fs/promises";
|
|
7399
7435
|
import path54 from "path";
|
|
@@ -7455,11 +7491,11 @@ var init_provenance = __esm(() => {
|
|
|
7455
7491
|
// src/ctx/orient.ts
|
|
7456
7492
|
var exports_orient = {};
|
|
7457
7493
|
__export(exports_orient, {
|
|
7458
|
-
|
|
7459
|
-
uncommittedCodeCount: () => uncommittedCodeCount,
|
|
7460
|
-
metaprojectIndexContext: () => metaprojectIndexContext,
|
|
7494
|
+
buildOrientation: () => buildOrientation,
|
|
7461
7495
|
graphContext: () => graphContext,
|
|
7462
|
-
|
|
7496
|
+
metaprojectIndexContext: () => metaprojectIndexContext,
|
|
7497
|
+
uncommittedCodeCount: () => uncommittedCodeCount,
|
|
7498
|
+
wikiContext: () => wikiContext
|
|
7463
7499
|
});
|
|
7464
7500
|
import path55 from "path";
|
|
7465
7501
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -7666,9 +7702,9 @@ var init_orient = __esm(() => {
|
|
|
7666
7702
|
// src/gdgraph/symbols-capability.ts
|
|
7667
7703
|
var exports_symbols_capability = {};
|
|
7668
7704
|
__export(exports_symbols_capability, {
|
|
7669
|
-
|
|
7705
|
+
TREESITTER_CAPABILITY: () => TREESITTER_CAPABILITY,
|
|
7670
7706
|
isTreesitterEnabled: () => isTreesitterEnabled,
|
|
7671
|
-
|
|
7707
|
+
setTreesitterEnabled: () => setTreesitterEnabled
|
|
7672
7708
|
});
|
|
7673
7709
|
function treesitterEntry(enabled) {
|
|
7674
7710
|
return {
|
|
@@ -8081,9 +8117,9 @@ function titleSimilarity(a, b) {
|
|
|
8081
8117
|
// src/wiki/collect.ts
|
|
8082
8118
|
var exports_collect = {};
|
|
8083
8119
|
__export(exports_collect, {
|
|
8084
|
-
|
|
8120
|
+
collectPages: () => collectPages,
|
|
8085
8121
|
computeModuleKeyFiles: () => computeModuleKeyFiles,
|
|
8086
|
-
|
|
8122
|
+
keyFilesForPage: () => keyFilesForPage
|
|
8087
8123
|
});
|
|
8088
8124
|
import { readFile as readFile29, readdir as readdir6 } from "fs/promises";
|
|
8089
8125
|
import path58 from "path";
|
|
@@ -8581,18 +8617,18 @@ var init_backlinks = __esm(() => {
|
|
|
8581
8617
|
// src/wiki/service.ts
|
|
8582
8618
|
var exports_service = {};
|
|
8583
8619
|
__export(exports_service, {
|
|
8584
|
-
|
|
8585
|
-
wikiStatus: () => wikiStatus,
|
|
8586
|
-
wikiPruneOrphans: () => wikiPruneOrphans,
|
|
8587
|
-
wikiPagesForFile: () => wikiPagesForFile,
|
|
8588
|
-
wikiGenerateIndex: () => wikiGenerateIndex,
|
|
8589
|
-
wikiCreatePage: () => wikiCreatePage,
|
|
8590
|
-
wikiCollect: () => wikiCollect,
|
|
8591
|
-
wikiCheckLinks: () => wikiCheckLinks,
|
|
8592
|
-
validModuleNames: () => validModuleNames,
|
|
8593
|
-
moduleNameFromProjectPath: () => moduleNameFromProjectPath,
|
|
8620
|
+
createGdWikiService: () => createGdWikiService,
|
|
8594
8621
|
extractModuleApi: () => extractModuleApi,
|
|
8595
|
-
|
|
8622
|
+
moduleNameFromProjectPath: () => moduleNameFromProjectPath,
|
|
8623
|
+
validModuleNames: () => validModuleNames,
|
|
8624
|
+
wikiCheckLinks: () => wikiCheckLinks,
|
|
8625
|
+
wikiCollect: () => wikiCollect,
|
|
8626
|
+
wikiCreatePage: () => wikiCreatePage,
|
|
8627
|
+
wikiGenerateIndex: () => wikiGenerateIndex,
|
|
8628
|
+
wikiPagesForFile: () => wikiPagesForFile,
|
|
8629
|
+
wikiPruneOrphans: () => wikiPruneOrphans,
|
|
8630
|
+
wikiStatus: () => wikiStatus,
|
|
8631
|
+
wikiValidate: () => wikiValidate
|
|
8596
8632
|
});
|
|
8597
8633
|
import { spawn as spawn3 } from "child_process";
|
|
8598
8634
|
import { mkdir as mkdir23, readFile as readFile30, readdir as readdir7, rm as rm3, writeFile as writeFile25 } from "fs/promises";
|
|
@@ -11454,9 +11490,396 @@ var init_anthropic_provider = __esm(() => {
|
|
|
11454
11490
|
};
|
|
11455
11491
|
});
|
|
11456
11492
|
|
|
11493
|
+
// src/harness/provider/compat/openai-compat-provider.ts
|
|
11494
|
+
function isPlainObject4(value) {
|
|
11495
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11496
|
+
}
|
|
11497
|
+
function asRecord3(value) {
|
|
11498
|
+
return isPlainObject4(value) ? value : {};
|
|
11499
|
+
}
|
|
11500
|
+
function asArray(value) {
|
|
11501
|
+
return Array.isArray(value) ? value : [];
|
|
11502
|
+
}
|
|
11503
|
+
function asString3(value) {
|
|
11504
|
+
return typeof value === "string" ? value : undefined;
|
|
11505
|
+
}
|
|
11506
|
+
function asNumber3(value) {
|
|
11507
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
11508
|
+
}
|
|
11509
|
+
function retryableFor2(kind, fallback) {
|
|
11510
|
+
const concrete = defaultRetryable(kind);
|
|
11511
|
+
return concrete === undefined ? fallback : concrete;
|
|
11512
|
+
}
|
|
11513
|
+
function mergeUsage2(promptTokens, completionTokens, totalTokens) {
|
|
11514
|
+
const usage = { exact: true };
|
|
11515
|
+
if (promptTokens !== undefined) {
|
|
11516
|
+
usage.inputTokens = promptTokens;
|
|
11517
|
+
}
|
|
11518
|
+
if (completionTokens !== undefined) {
|
|
11519
|
+
usage.outputTokens = completionTokens;
|
|
11520
|
+
}
|
|
11521
|
+
if (totalTokens !== undefined) {
|
|
11522
|
+
usage.totalTokens = totalTokens;
|
|
11523
|
+
} else if (promptTokens !== undefined || completionTokens !== undefined) {
|
|
11524
|
+
usage.totalTokens = (promptTokens ?? 0) + (completionTokens ?? 0);
|
|
11525
|
+
}
|
|
11526
|
+
return usage;
|
|
11527
|
+
}
|
|
11528
|
+
function classifyHttpError2(status) {
|
|
11529
|
+
if (status >= 500) {
|
|
11530
|
+
return { kind: "unavailable", retryable: retryableFor2("unavailable", true), message: "" };
|
|
11531
|
+
}
|
|
11532
|
+
return { kind: "invalid_request", retryable: retryableFor2("invalid_request", false), message: "" };
|
|
11533
|
+
}
|
|
11534
|
+
|
|
11535
|
+
class OpenAiCompatEngine {
|
|
11536
|
+
deps;
|
|
11537
|
+
identity;
|
|
11538
|
+
constructor(deps, identity) {
|
|
11539
|
+
this.deps = deps;
|
|
11540
|
+
this.identity = identity;
|
|
11541
|
+
}
|
|
11542
|
+
get label() {
|
|
11543
|
+
return this.identity.providerLabel ?? this.identity.providerId;
|
|
11544
|
+
}
|
|
11545
|
+
describe() {
|
|
11546
|
+
const capabilities = {
|
|
11547
|
+
streaming: true,
|
|
11548
|
+
toolCalls: true,
|
|
11549
|
+
parallelToolCalls: true,
|
|
11550
|
+
structuredOutput: false,
|
|
11551
|
+
reasoningMetadata: false,
|
|
11552
|
+
promptCaching: false,
|
|
11553
|
+
vision: false,
|
|
11554
|
+
tokenCounting: false,
|
|
11555
|
+
modelListing: false
|
|
11556
|
+
};
|
|
11557
|
+
return {
|
|
11558
|
+
capabilities,
|
|
11559
|
+
descriptor: { providerId: this.identity.providerId, providerRevision: this.identity.providerRevision }
|
|
11560
|
+
};
|
|
11561
|
+
}
|
|
11562
|
+
descriptorDocument() {
|
|
11563
|
+
return {
|
|
11564
|
+
schemaVersion: 1,
|
|
11565
|
+
providerId: this.identity.providerId,
|
|
11566
|
+
providerRevision: this.identity.providerRevision,
|
|
11567
|
+
models: [{ modelId: this.identity.defaultModel.modelId, revision: this.identity.defaultModel.revision }],
|
|
11568
|
+
capabilities: {
|
|
11569
|
+
streaming: true,
|
|
11570
|
+
tools: true,
|
|
11571
|
+
parallelToolCalls: true,
|
|
11572
|
+
cancellation: true,
|
|
11573
|
+
structuredOutput: false
|
|
11574
|
+
},
|
|
11575
|
+
remoteState: { storage: false, retention: false, continuation: false }
|
|
11576
|
+
};
|
|
11577
|
+
}
|
|
11578
|
+
async* stream(request, opts) {
|
|
11579
|
+
let sequence = 0;
|
|
11580
|
+
const stamp = (body) => ({ ...body, sequence: sequence++, attemptId: opts.attemptId });
|
|
11581
|
+
const errorEvent = (error) => stamp({ kind: "provider_error", error });
|
|
11582
|
+
const grant = this.deps.grant;
|
|
11583
|
+
if (grant === undefined || grant.network !== true) {
|
|
11584
|
+
yield errorEvent({
|
|
11585
|
+
kind: "invalid_request",
|
|
11586
|
+
retryable: retryableFor2("invalid_request", false),
|
|
11587
|
+
message: `a network capability grant is required to reach the ${this.label} API`
|
|
11588
|
+
});
|
|
11589
|
+
return;
|
|
11590
|
+
}
|
|
11591
|
+
const baseUrl = grant.baseUrl ?? this.identity.defaultBaseUrl;
|
|
11592
|
+
let host;
|
|
11593
|
+
try {
|
|
11594
|
+
host = new URL(baseUrl).hostname;
|
|
11595
|
+
} catch {
|
|
11596
|
+
host = baseUrl;
|
|
11597
|
+
}
|
|
11598
|
+
const permitted = !isPrivateEgressHost(host) || grant.allowLoopback === true && isLoopbackHost(host);
|
|
11599
|
+
if (!permitted) {
|
|
11600
|
+
yield errorEvent({
|
|
11601
|
+
kind: "invalid_request",
|
|
11602
|
+
retryable: retryableFor2("invalid_request", false),
|
|
11603
|
+
message: `egress to a private/loopback/link-local/metadata host is denied: ${host}`
|
|
11604
|
+
});
|
|
11605
|
+
return;
|
|
11606
|
+
}
|
|
11607
|
+
const url = `${baseUrl.replace(/\/+$/, "")}${grant.chatPath ?? "/v1/chat/completions"}`;
|
|
11608
|
+
const messages = [];
|
|
11609
|
+
if (request.systemInstruction.length > 0) {
|
|
11610
|
+
messages.push({ role: "system", content: request.systemInstruction });
|
|
11611
|
+
}
|
|
11612
|
+
for (const linked of linkToolCalls(request.messages)) {
|
|
11613
|
+
const message = linked.message;
|
|
11614
|
+
if (message.role === "tool") {
|
|
11615
|
+
if (linked.linkedToolCallId !== undefined) {
|
|
11616
|
+
messages.push({ role: "tool", tool_call_id: linked.linkedToolCallId, content: message.content });
|
|
11617
|
+
continue;
|
|
11618
|
+
}
|
|
11619
|
+
messages.push({ role: "user", content: `Tool result:
|
|
11620
|
+
${message.content}` });
|
|
11621
|
+
continue;
|
|
11622
|
+
}
|
|
11623
|
+
if (message.role === "assistant" && message.content.length === 0 && linked.linkedCalls.length === 0) {
|
|
11624
|
+
continue;
|
|
11625
|
+
}
|
|
11626
|
+
if (message.role === "assistant" && linked.linkedCalls.length > 0) {
|
|
11627
|
+
messages.push({
|
|
11628
|
+
role: "assistant",
|
|
11629
|
+
content: message.content,
|
|
11630
|
+
tool_calls: linked.linkedCalls.map((call) => ({
|
|
11631
|
+
id: call.id,
|
|
11632
|
+
type: "function",
|
|
11633
|
+
function: { name: call.name, arguments: call.arguments }
|
|
11634
|
+
}))
|
|
11635
|
+
});
|
|
11636
|
+
continue;
|
|
11637
|
+
}
|
|
11638
|
+
messages.push({ role: message.role, content: message.content });
|
|
11639
|
+
}
|
|
11640
|
+
const payload = {
|
|
11641
|
+
model: request.modelId,
|
|
11642
|
+
stream: true,
|
|
11643
|
+
messages,
|
|
11644
|
+
...request.tools !== undefined ? {
|
|
11645
|
+
tools: request.tools.map((tool) => ({
|
|
11646
|
+
type: "function",
|
|
11647
|
+
function: {
|
|
11648
|
+
name: tool.name,
|
|
11649
|
+
...tool.description !== undefined ? { description: tool.description } : {},
|
|
11650
|
+
parameters: tool.inputSchema
|
|
11651
|
+
}
|
|
11652
|
+
}))
|
|
11653
|
+
} : {}
|
|
11654
|
+
};
|
|
11655
|
+
const headers = { "content-type": "application/json" };
|
|
11656
|
+
if (grant.apiKey !== undefined && grant.apiKey.length > 0) {
|
|
11657
|
+
headers.authorization = `Bearer ${grant.apiKey}`;
|
|
11658
|
+
}
|
|
11659
|
+
if (grant.headers !== undefined) {
|
|
11660
|
+
Object.assign(headers, grant.headers);
|
|
11661
|
+
}
|
|
11662
|
+
const init = {
|
|
11663
|
+
method: "POST",
|
|
11664
|
+
headers,
|
|
11665
|
+
body: JSON.stringify(payload),
|
|
11666
|
+
...opts.signal !== undefined ? { signal: opts.signal } : {}
|
|
11667
|
+
};
|
|
11668
|
+
let response;
|
|
11669
|
+
try {
|
|
11670
|
+
response = await this.deps.fetch(url, init);
|
|
11671
|
+
} catch (cause) {
|
|
11672
|
+
if (opts.signal?.aborted === true) {
|
|
11673
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor2("cancelled", false), message: "attempt cancelled" });
|
|
11674
|
+
return;
|
|
11675
|
+
}
|
|
11676
|
+
yield errorEvent({
|
|
11677
|
+
kind: "unavailable",
|
|
11678
|
+
retryable: retryableFor2("unavailable", true),
|
|
11679
|
+
message: `network request to the ${this.label} API failed: ${String(cause)}`
|
|
11680
|
+
});
|
|
11681
|
+
return;
|
|
11682
|
+
}
|
|
11683
|
+
if (!response.ok) {
|
|
11684
|
+
const error = classifyHttpError2(response.status);
|
|
11685
|
+
let providerMessage = `${this.label} API returned HTTP ${response.status}`;
|
|
11686
|
+
try {
|
|
11687
|
+
const parsed = asRecord3(JSON.parse(await response.text()));
|
|
11688
|
+
const detail = asString3(asRecord3(parsed.error).message);
|
|
11689
|
+
if (detail !== undefined && detail.length > 0) {
|
|
11690
|
+
providerMessage = detail;
|
|
11691
|
+
}
|
|
11692
|
+
} catch {}
|
|
11693
|
+
error.message = providerMessage;
|
|
11694
|
+
yield stamp({ kind: "provider_error", error });
|
|
11695
|
+
return;
|
|
11696
|
+
}
|
|
11697
|
+
let bodyText;
|
|
11698
|
+
try {
|
|
11699
|
+
bodyText = await response.text();
|
|
11700
|
+
} catch (cause) {
|
|
11701
|
+
const aborted = opts.signal?.aborted === true || typeof cause === "object" && cause !== null && cause.name === "AbortError";
|
|
11702
|
+
if (aborted) {
|
|
11703
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor2("cancelled", false), message: "attempt cancelled" });
|
|
11704
|
+
return;
|
|
11705
|
+
}
|
|
11706
|
+
yield errorEvent({
|
|
11707
|
+
kind: "malformed",
|
|
11708
|
+
retryable: retryableFor2("malformed", false),
|
|
11709
|
+
message: `${this.label} SSE body read failed: ${String(cause)}`
|
|
11710
|
+
});
|
|
11711
|
+
return;
|
|
11712
|
+
}
|
|
11713
|
+
if (bodyText.length === 0) {
|
|
11714
|
+
yield errorEvent({
|
|
11715
|
+
kind: "malformed",
|
|
11716
|
+
retryable: retryableFor2("malformed", false),
|
|
11717
|
+
message: "empty response body"
|
|
11718
|
+
});
|
|
11719
|
+
return;
|
|
11720
|
+
}
|
|
11721
|
+
const parser = new AnthropicSSEParser;
|
|
11722
|
+
const records = parser.push(bodyText);
|
|
11723
|
+
const torn = parser.flush();
|
|
11724
|
+
const bodies = [];
|
|
11725
|
+
let sawStart = false;
|
|
11726
|
+
let sawFinish = false;
|
|
11727
|
+
let sawDone = false;
|
|
11728
|
+
let malformed;
|
|
11729
|
+
const pendingTools = new Map;
|
|
11730
|
+
const toolCallKey = (toolCall) => {
|
|
11731
|
+
const index = asNumber3(toolCall.index);
|
|
11732
|
+
if (index !== undefined) {
|
|
11733
|
+
return `idx:${index}`;
|
|
11734
|
+
}
|
|
11735
|
+
const id = asString3(toolCall.id);
|
|
11736
|
+
if (id !== undefined && id.length > 0) {
|
|
11737
|
+
return `id:${id}`;
|
|
11738
|
+
}
|
|
11739
|
+
return "idx:0";
|
|
11740
|
+
};
|
|
11741
|
+
const flushPendingToolEnds = () => {
|
|
11742
|
+
for (const acc of pendingTools.values()) {
|
|
11743
|
+
if (acc.ended) {
|
|
11744
|
+
continue;
|
|
11745
|
+
}
|
|
11746
|
+
if (!acc.started) {
|
|
11747
|
+
const startBody = { kind: "tool_call_start", toolCallId: acc.id };
|
|
11748
|
+
if (acc.name.length > 0) {
|
|
11749
|
+
startBody.toolName = acc.name;
|
|
11750
|
+
}
|
|
11751
|
+
bodies.push(startBody);
|
|
11752
|
+
acc.started = true;
|
|
11753
|
+
}
|
|
11754
|
+
bodies.push({ kind: "tool_call_end", toolCallId: acc.id, input: acc.arguments });
|
|
11755
|
+
acc.ended = true;
|
|
11756
|
+
}
|
|
11757
|
+
pendingTools.clear();
|
|
11758
|
+
};
|
|
11759
|
+
for (const record of records) {
|
|
11760
|
+
const trimmed = record.data.trim();
|
|
11761
|
+
if (trimmed === "[DONE]") {
|
|
11762
|
+
sawDone = true;
|
|
11763
|
+
flushPendingToolEnds();
|
|
11764
|
+
continue;
|
|
11765
|
+
}
|
|
11766
|
+
if (!sawStart) {
|
|
11767
|
+
sawStart = true;
|
|
11768
|
+
bodies.push({ kind: "model_start" });
|
|
11769
|
+
}
|
|
11770
|
+
let parsed;
|
|
11771
|
+
try {
|
|
11772
|
+
parsed = JSON.parse(record.data);
|
|
11773
|
+
} catch {
|
|
11774
|
+
malformed = {
|
|
11775
|
+
kind: "malformed",
|
|
11776
|
+
retryable: retryableFor2("malformed", false),
|
|
11777
|
+
message: `${this.label} SSE data line was not valid JSON`
|
|
11778
|
+
};
|
|
11779
|
+
break;
|
|
11780
|
+
}
|
|
11781
|
+
const data = asRecord3(parsed);
|
|
11782
|
+
if (data.usage !== undefined) {
|
|
11783
|
+
const usage = asRecord3(data.usage);
|
|
11784
|
+
bodies.push({
|
|
11785
|
+
kind: "usage_update",
|
|
11786
|
+
usage: mergeUsage2(asNumber3(usage.prompt_tokens), asNumber3(usage.completion_tokens), asNumber3(usage.total_tokens))
|
|
11787
|
+
});
|
|
11788
|
+
}
|
|
11789
|
+
const choice0 = asRecord3(asArray(data.choices)[0]);
|
|
11790
|
+
const delta = asRecord3(choice0.delta);
|
|
11791
|
+
const reasoning = asString3(delta.reasoning) ?? asString3(delta.reasoning_content);
|
|
11792
|
+
if (reasoning !== undefined && reasoning.length > 0) {
|
|
11793
|
+
bodies.push({ kind: "reasoning_delta", text: reasoning });
|
|
11794
|
+
}
|
|
11795
|
+
const content = asString3(delta.content);
|
|
11796
|
+
if (content !== undefined && content.length > 0) {
|
|
11797
|
+
bodies.push({ kind: "text_delta", text: content });
|
|
11798
|
+
}
|
|
11799
|
+
for (const rawToolCall of asArray(delta.tool_calls)) {
|
|
11800
|
+
const toolCall = asRecord3(rawToolCall);
|
|
11801
|
+
const fn = asRecord3(toolCall.function);
|
|
11802
|
+
const toolCallId = asString3(toolCall.id);
|
|
11803
|
+
const toolName = asString3(fn.name);
|
|
11804
|
+
const argumentsFragment = asString3(fn.arguments) ?? "";
|
|
11805
|
+
const key = toolCallKey(toolCall);
|
|
11806
|
+
let acc = pendingTools.get(key);
|
|
11807
|
+
if (acc === undefined) {
|
|
11808
|
+
acc = {
|
|
11809
|
+
id: toolCallId ?? `call_${key.replace(/[^a-zA-Z0-9_:-]/g, "_")}`,
|
|
11810
|
+
name: toolName ?? "",
|
|
11811
|
+
arguments: "",
|
|
11812
|
+
started: false,
|
|
11813
|
+
ended: false
|
|
11814
|
+
};
|
|
11815
|
+
pendingTools.set(key, acc);
|
|
11816
|
+
}
|
|
11817
|
+
if (toolCallId !== undefined && toolCallId.length > 0) {
|
|
11818
|
+
acc.id = toolCallId;
|
|
11819
|
+
}
|
|
11820
|
+
if (toolName !== undefined && toolName.length > 0) {
|
|
11821
|
+
acc.name = toolName;
|
|
11822
|
+
}
|
|
11823
|
+
if (!acc.started) {
|
|
11824
|
+
const startBody = { kind: "tool_call_start", toolCallId: acc.id };
|
|
11825
|
+
if (acc.name.length > 0) {
|
|
11826
|
+
startBody.toolName = acc.name;
|
|
11827
|
+
}
|
|
11828
|
+
bodies.push(startBody);
|
|
11829
|
+
acc.started = true;
|
|
11830
|
+
}
|
|
11831
|
+
if (argumentsFragment.length > 0) {
|
|
11832
|
+
acc.arguments += argumentsFragment;
|
|
11833
|
+
bodies.push({
|
|
11834
|
+
kind: "tool_call_delta",
|
|
11835
|
+
toolCallId: acc.id,
|
|
11836
|
+
inputDelta: argumentsFragment
|
|
11837
|
+
});
|
|
11838
|
+
}
|
|
11839
|
+
}
|
|
11840
|
+
const finishReason = asString3(choice0.finish_reason);
|
|
11841
|
+
if (finishReason !== undefined && finishReason.length > 0) {
|
|
11842
|
+
sawFinish = true;
|
|
11843
|
+
flushPendingToolEnds();
|
|
11844
|
+
}
|
|
11845
|
+
}
|
|
11846
|
+
if (malformed === undefined && torn.length > 0) {
|
|
11847
|
+
malformed = {
|
|
11848
|
+
kind: "malformed",
|
|
11849
|
+
retryable: retryableFor2("malformed", false),
|
|
11850
|
+
message: `${this.label} SSE stream ended mid-record (torn stream)`
|
|
11851
|
+
};
|
|
11852
|
+
}
|
|
11853
|
+
if (malformed === undefined) {
|
|
11854
|
+
flushPendingToolEnds();
|
|
11855
|
+
}
|
|
11856
|
+
if (malformed === undefined && sawStart && (sawDone || sawFinish)) {
|
|
11857
|
+
bodies.push({ kind: "model_end" });
|
|
11858
|
+
}
|
|
11859
|
+
for (const body of bodies) {
|
|
11860
|
+
if (opts.signal?.aborted === true) {
|
|
11861
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor2("cancelled", false), message: "attempt cancelled" });
|
|
11862
|
+
return;
|
|
11863
|
+
}
|
|
11864
|
+
yield stamp(body);
|
|
11865
|
+
}
|
|
11866
|
+
if (opts.signal?.aborted === true) {
|
|
11867
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor2("cancelled", false), message: "attempt cancelled" });
|
|
11868
|
+
return;
|
|
11869
|
+
}
|
|
11870
|
+
if (malformed !== undefined) {
|
|
11871
|
+
yield stamp({ kind: "provider_error", error: malformed });
|
|
11872
|
+
}
|
|
11873
|
+
}
|
|
11874
|
+
}
|
|
11875
|
+
var init_openai_compat_provider = __esm(() => {
|
|
11876
|
+
init_guard2();
|
|
11877
|
+
init_provider_port();
|
|
11878
|
+
});
|
|
11879
|
+
|
|
11457
11880
|
// src/harness/provider/fake-provider.ts
|
|
11458
11881
|
import { createHash as createHash5 } from "crypto";
|
|
11459
|
-
function
|
|
11882
|
+
function isPlainObject5(value) {
|
|
11460
11883
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11461
11884
|
}
|
|
11462
11885
|
function canonicalize(value) {
|
|
@@ -11483,7 +11906,7 @@ function requestHashOf(request) {
|
|
|
11483
11906
|
}
|
|
11484
11907
|
function extractUnknownExtensions(payload) {
|
|
11485
11908
|
const provider = payload.provider;
|
|
11486
|
-
if (!
|
|
11909
|
+
if (!isPlainObject5(provider)) {
|
|
11487
11910
|
return;
|
|
11488
11911
|
}
|
|
11489
11912
|
const extensions = {};
|
|
@@ -11561,7 +11984,7 @@ class FakeProvider {
|
|
|
11561
11984
|
}
|
|
11562
11985
|
case "tool_call": {
|
|
11563
11986
|
const input2 = payload.input;
|
|
11564
|
-
if (!
|
|
11987
|
+
if (!isPlainObject5(input2)) {
|
|
11565
11988
|
yield emit({
|
|
11566
11989
|
kind: "provider_error",
|
|
11567
11990
|
error: {
|
|
@@ -11587,7 +12010,7 @@ class FakeProvider {
|
|
|
11587
12010
|
}
|
|
11588
12011
|
case "finish": {
|
|
11589
12012
|
const usage = payload.usage;
|
|
11590
|
-
if (
|
|
12013
|
+
if (isPlainObject5(usage)) {
|
|
11591
12014
|
yield emit({ kind: "usage_update", usage: mapUsage(usage) });
|
|
11592
12015
|
}
|
|
11593
12016
|
const body = { kind: "model_end" };
|
|
@@ -11615,49 +12038,143 @@ var init_fake_provider = __esm(() => {
|
|
|
11615
12038
|
init_provider_port();
|
|
11616
12039
|
});
|
|
11617
12040
|
|
|
11618
|
-
// src/harness/provider/
|
|
11619
|
-
function
|
|
12041
|
+
// src/harness/provider/gemini/gemini-provider.ts
|
|
12042
|
+
function isPlainObject6(value) {
|
|
11620
12043
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11621
12044
|
}
|
|
11622
|
-
function
|
|
11623
|
-
return
|
|
12045
|
+
function asRecord4(value) {
|
|
12046
|
+
return isPlainObject6(value) ? value : {};
|
|
11624
12047
|
}
|
|
11625
|
-
function
|
|
12048
|
+
function asArray2(value) {
|
|
11626
12049
|
return Array.isArray(value) ? value : [];
|
|
11627
12050
|
}
|
|
11628
|
-
function
|
|
12051
|
+
function asString4(value) {
|
|
11629
12052
|
return typeof value === "string" ? value : undefined;
|
|
11630
12053
|
}
|
|
11631
|
-
function
|
|
12054
|
+
function asNumber4(value) {
|
|
11632
12055
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
11633
12056
|
}
|
|
11634
|
-
function
|
|
12057
|
+
function asBoolean(value) {
|
|
12058
|
+
return value === true;
|
|
12059
|
+
}
|
|
12060
|
+
function toGeminiContents(messages) {
|
|
12061
|
+
const out = [];
|
|
12062
|
+
for (const linked of linkToolCalls(messages)) {
|
|
12063
|
+
const message = linked.message;
|
|
12064
|
+
if (message.role === "system") {
|
|
12065
|
+
continue;
|
|
12066
|
+
}
|
|
12067
|
+
if (message.role === "assistant" && message.content.length === 0 && linked.linkedCalls.length === 0) {
|
|
12068
|
+
continue;
|
|
12069
|
+
}
|
|
12070
|
+
if (message.role === "tool" && linked.linkedToolCallId !== undefined) {
|
|
12071
|
+
const call = linked.message.toolCallId;
|
|
12072
|
+
out.push({
|
|
12073
|
+
role: "user",
|
|
12074
|
+
parts: [
|
|
12075
|
+
{
|
|
12076
|
+
functionResponse: {
|
|
12077
|
+
name: findToolName(messages, linked.linkedToolCallId) ?? "",
|
|
12078
|
+
id: call,
|
|
12079
|
+
response: parseFunctionResponse(message.content)
|
|
12080
|
+
}
|
|
12081
|
+
}
|
|
12082
|
+
]
|
|
12083
|
+
});
|
|
12084
|
+
continue;
|
|
12085
|
+
}
|
|
12086
|
+
if (message.role === "assistant" && linked.linkedCalls.length > 0) {
|
|
12087
|
+
const parts = [];
|
|
12088
|
+
if (message.content.length > 0) {
|
|
12089
|
+
parts.push({ text: message.content });
|
|
12090
|
+
}
|
|
12091
|
+
for (const call of linked.linkedCalls) {
|
|
12092
|
+
parts.push({
|
|
12093
|
+
functionCall: { name: call.name, id: call.id, args: parseToolInput2(call.arguments) }
|
|
12094
|
+
});
|
|
12095
|
+
}
|
|
12096
|
+
out.push({ role: "model", parts });
|
|
12097
|
+
continue;
|
|
12098
|
+
}
|
|
12099
|
+
out.push({
|
|
12100
|
+
role: message.role === "assistant" ? "model" : "user",
|
|
12101
|
+
parts: [{ text: message.content }]
|
|
12102
|
+
});
|
|
12103
|
+
}
|
|
12104
|
+
return out;
|
|
12105
|
+
}
|
|
12106
|
+
function findToolName(messages, toolCallId) {
|
|
12107
|
+
for (const message of messages) {
|
|
12108
|
+
if (message.role !== "assistant" || !Array.isArray(message.toolCalls)) {
|
|
12109
|
+
continue;
|
|
12110
|
+
}
|
|
12111
|
+
const match = message.toolCalls.find((call) => call.id === toolCallId);
|
|
12112
|
+
if (match !== undefined) {
|
|
12113
|
+
return match.name;
|
|
12114
|
+
}
|
|
12115
|
+
}
|
|
12116
|
+
return;
|
|
12117
|
+
}
|
|
12118
|
+
function parseFunctionResponse(rawContent) {
|
|
12119
|
+
if (rawContent.trim().length === 0) {
|
|
12120
|
+
return {};
|
|
12121
|
+
}
|
|
12122
|
+
try {
|
|
12123
|
+
const parsed = JSON.parse(rawContent);
|
|
12124
|
+
return isPlainObject6(parsed) ? parsed : { result: parsed };
|
|
12125
|
+
} catch {
|
|
12126
|
+
return { result: rawContent };
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
12129
|
+
function parseToolInput2(rawArguments) {
|
|
12130
|
+
if (rawArguments.trim().length === 0) {
|
|
12131
|
+
return {};
|
|
12132
|
+
}
|
|
12133
|
+
try {
|
|
12134
|
+
return asRecord4(JSON.parse(rawArguments));
|
|
12135
|
+
} catch {
|
|
12136
|
+
return {};
|
|
12137
|
+
}
|
|
12138
|
+
}
|
|
12139
|
+
function retryableFor3(kind, fallback) {
|
|
11635
12140
|
const concrete = defaultRetryable(kind);
|
|
11636
12141
|
return concrete === undefined ? fallback : concrete;
|
|
11637
12142
|
}
|
|
11638
|
-
function
|
|
12143
|
+
function mergeUsage3(promptTokens, candidatesTokens, totalTokens) {
|
|
11639
12144
|
const usage = { exact: true };
|
|
11640
12145
|
if (promptTokens !== undefined) {
|
|
11641
12146
|
usage.inputTokens = promptTokens;
|
|
11642
12147
|
}
|
|
11643
|
-
if (
|
|
11644
|
-
usage.outputTokens =
|
|
12148
|
+
if (candidatesTokens !== undefined) {
|
|
12149
|
+
usage.outputTokens = candidatesTokens;
|
|
11645
12150
|
}
|
|
11646
12151
|
if (totalTokens !== undefined) {
|
|
11647
12152
|
usage.totalTokens = totalTokens;
|
|
11648
|
-
} else if (promptTokens !== undefined ||
|
|
11649
|
-
usage.totalTokens = (promptTokens ?? 0) + (
|
|
12153
|
+
} else if (promptTokens !== undefined || candidatesTokens !== undefined) {
|
|
12154
|
+
usage.totalTokens = (promptTokens ?? 0) + (candidatesTokens ?? 0);
|
|
11650
12155
|
}
|
|
11651
12156
|
return usage;
|
|
11652
12157
|
}
|
|
11653
|
-
function
|
|
11654
|
-
if (
|
|
11655
|
-
return { kind: "
|
|
12158
|
+
function classifyGeminiError(httpStatus, rpcStatus) {
|
|
12159
|
+
if (rpcStatus === "UNAUTHENTICATED" || httpStatus === 401 || httpStatus === 403) {
|
|
12160
|
+
return { kind: "authentication", retryable: retryableFor3("authentication", false), message: "" };
|
|
11656
12161
|
}
|
|
11657
|
-
|
|
12162
|
+
if (rpcStatus === "RESOURCE_EXHAUSTED" || httpStatus === 429) {
|
|
12163
|
+
return { kind: "rate_limit", retryable: retryableFor3("rate_limit", true), message: "" };
|
|
12164
|
+
}
|
|
12165
|
+
if (rpcStatus === "UNAVAILABLE" || httpStatus >= 500) {
|
|
12166
|
+
return { kind: "unavailable", retryable: retryableFor3("unavailable", true), message: "" };
|
|
12167
|
+
}
|
|
12168
|
+
if (rpcStatus === "INVALID_ARGUMENT" || httpStatus === 400) {
|
|
12169
|
+
return { kind: "invalid_request", retryable: retryableFor3("invalid_request", false), message: "" };
|
|
12170
|
+
}
|
|
12171
|
+
if (httpStatus >= 400) {
|
|
12172
|
+
return { kind: "invalid_request", retryable: retryableFor3("invalid_request", false), message: "" };
|
|
12173
|
+
}
|
|
12174
|
+
return { kind: "unknown", retryable: retryableFor3("unknown", false), message: "" };
|
|
11658
12175
|
}
|
|
11659
12176
|
|
|
11660
|
-
class
|
|
12177
|
+
class GeminiProvider {
|
|
11661
12178
|
deps;
|
|
11662
12179
|
constructor(deps) {
|
|
11663
12180
|
this.deps = deps;
|
|
@@ -11667,22 +12184,22 @@ class OllamaProvider {
|
|
|
11667
12184
|
streaming: true,
|
|
11668
12185
|
toolCalls: true,
|
|
11669
12186
|
parallelToolCalls: true,
|
|
11670
|
-
structuredOutput:
|
|
11671
|
-
reasoningMetadata:
|
|
11672
|
-
promptCaching:
|
|
11673
|
-
vision:
|
|
12187
|
+
structuredOutput: true,
|
|
12188
|
+
reasoningMetadata: true,
|
|
12189
|
+
promptCaching: true,
|
|
12190
|
+
vision: true,
|
|
11674
12191
|
tokenCounting: false,
|
|
11675
12192
|
modelListing: false
|
|
11676
12193
|
};
|
|
11677
12194
|
return {
|
|
11678
12195
|
capabilities,
|
|
11679
|
-
descriptor: { providerId: "
|
|
12196
|
+
descriptor: { providerId: "gemini", providerRevision: PROVIDER_REVISION2 }
|
|
11680
12197
|
};
|
|
11681
12198
|
}
|
|
11682
12199
|
descriptorDocument() {
|
|
11683
12200
|
return {
|
|
11684
12201
|
schemaVersion: 1,
|
|
11685
|
-
providerId: "
|
|
12202
|
+
providerId: "gemini",
|
|
11686
12203
|
providerRevision: PROVIDER_REVISION2,
|
|
11687
12204
|
models: [{ modelId: DEFAULT_MODEL2.modelId, revision: DEFAULT_MODEL2.revision }],
|
|
11688
12205
|
capabilities: {
|
|
@@ -11690,7 +12207,7 @@ class OllamaProvider {
|
|
|
11690
12207
|
tools: true,
|
|
11691
12208
|
parallelToolCalls: true,
|
|
11692
12209
|
cancellation: true,
|
|
11693
|
-
structuredOutput:
|
|
12210
|
+
structuredOutput: true
|
|
11694
12211
|
},
|
|
11695
12212
|
remoteState: { storage: false, retention: false, continuation: false }
|
|
11696
12213
|
};
|
|
@@ -11700,11 +12217,12 @@ class OllamaProvider {
|
|
|
11700
12217
|
const stamp = (body) => ({ ...body, sequence: sequence++, attemptId: opts.attemptId });
|
|
11701
12218
|
const errorEvent = (error) => stamp({ kind: "provider_error", error });
|
|
11702
12219
|
const grant = this.deps.grant;
|
|
11703
|
-
|
|
12220
|
+
const redact = (message) => grant !== undefined && grant.apiKey.length > 0 ? message.split(grant.apiKey).join("[redacted]") : message;
|
|
12221
|
+
if (grant === undefined || grant.network !== true || typeof grant.apiKey !== "string" || grant.apiKey.length === 0) {
|
|
11704
12222
|
yield errorEvent({
|
|
11705
|
-
kind: "
|
|
11706
|
-
retryable:
|
|
11707
|
-
message: "
|
|
12223
|
+
kind: "authentication",
|
|
12224
|
+
retryable: retryableFor3("authentication", false),
|
|
12225
|
+
message: "network capability grant with an apiKey is required to reach the Gemini API"
|
|
11708
12226
|
});
|
|
11709
12227
|
return;
|
|
11710
12228
|
}
|
|
@@ -11715,70 +12233,459 @@ class OllamaProvider {
|
|
|
11715
12233
|
} catch {
|
|
11716
12234
|
host = baseUrl;
|
|
11717
12235
|
}
|
|
11718
|
-
|
|
11719
|
-
if (!permitted) {
|
|
12236
|
+
if (isPrivateEgressHost(host)) {
|
|
11720
12237
|
yield errorEvent({
|
|
11721
12238
|
kind: "invalid_request",
|
|
11722
|
-
retryable:
|
|
11723
|
-
message: `egress to a private/loopback/link-local/metadata host is denied: ${host}`
|
|
12239
|
+
retryable: retryableFor3("invalid_request", false),
|
|
12240
|
+
message: redact(`egress to a private/loopback/link-local/metadata host is denied: ${host}`)
|
|
11724
12241
|
});
|
|
11725
12242
|
return;
|
|
11726
12243
|
}
|
|
11727
|
-
const url = `${baseUrl.replace(/\/+$/, "")}
|
|
11728
|
-
const
|
|
11729
|
-
|
|
11730
|
-
|
|
12244
|
+
const url = `${baseUrl.replace(/\/+$/, "")}/v1beta/models/${encodeURIComponent(request.modelId)}:streamGenerateContent?alt=sse`;
|
|
12245
|
+
const headers = {
|
|
12246
|
+
"x-goog-api-key": grant.apiKey,
|
|
12247
|
+
"content-type": "application/json"
|
|
12248
|
+
};
|
|
12249
|
+
const payload = {
|
|
12250
|
+
contents: toGeminiContents(request.messages),
|
|
12251
|
+
...request.systemInstruction.length > 0 ? { systemInstruction: { parts: [{ text: request.systemInstruction }] } } : {},
|
|
12252
|
+
...request.tools !== undefined && request.tools.length > 0 ? {
|
|
12253
|
+
tools: [
|
|
12254
|
+
{
|
|
12255
|
+
functionDeclarations: request.tools.map((tool) => ({
|
|
12256
|
+
name: tool.name,
|
|
12257
|
+
...tool.description !== undefined ? { description: tool.description } : {},
|
|
12258
|
+
parameters: tool.inputSchema
|
|
12259
|
+
}))
|
|
12260
|
+
}
|
|
12261
|
+
]
|
|
12262
|
+
} : {},
|
|
12263
|
+
generationConfig: {
|
|
12264
|
+
maxOutputTokens: request.budget.maxOutputTokens,
|
|
12265
|
+
...request.options?.temperature !== undefined ? { temperature: request.options.temperature } : {}
|
|
12266
|
+
}
|
|
12267
|
+
};
|
|
12268
|
+
const init = {
|
|
12269
|
+
method: "POST",
|
|
12270
|
+
headers,
|
|
12271
|
+
body: JSON.stringify(payload),
|
|
12272
|
+
...opts.signal !== undefined ? { signal: opts.signal } : {}
|
|
12273
|
+
};
|
|
12274
|
+
let response;
|
|
12275
|
+
try {
|
|
12276
|
+
response = await this.deps.fetch(url, init);
|
|
12277
|
+
} catch (cause) {
|
|
12278
|
+
if (opts.signal?.aborted === true) {
|
|
12279
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor3("cancelled", false), message: "attempt cancelled" });
|
|
12280
|
+
return;
|
|
12281
|
+
}
|
|
12282
|
+
yield errorEvent({
|
|
12283
|
+
kind: "unavailable",
|
|
12284
|
+
retryable: retryableFor3("unavailable", true),
|
|
12285
|
+
message: redact(`network request to the Gemini API failed: ${String(cause)}`)
|
|
12286
|
+
});
|
|
12287
|
+
return;
|
|
11731
12288
|
}
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
|
|
11736
|
-
|
|
12289
|
+
if (!response.ok) {
|
|
12290
|
+
let error;
|
|
12291
|
+
let providerMessage = `Gemini API returned HTTP ${response.status}`;
|
|
12292
|
+
try {
|
|
12293
|
+
const parsed = asRecord4(JSON.parse(await response.text()));
|
|
12294
|
+
const envelope = asRecord4(parsed.error);
|
|
12295
|
+
const rpcStatus = asString4(envelope.status);
|
|
12296
|
+
const httpCode = asNumber4(envelope.code) ?? response.status;
|
|
12297
|
+
error = classifyGeminiError(httpCode, rpcStatus);
|
|
12298
|
+
const detail = asString4(envelope.message);
|
|
12299
|
+
if (detail !== undefined && detail.length > 0) {
|
|
12300
|
+
providerMessage = detail;
|
|
12301
|
+
}
|
|
12302
|
+
} catch {
|
|
12303
|
+
error = classifyGeminiError(response.status, undefined);
|
|
12304
|
+
}
|
|
12305
|
+
error.message = redact(providerMessage);
|
|
12306
|
+
yield stamp({ kind: "provider_error", error });
|
|
12307
|
+
return;
|
|
12308
|
+
}
|
|
12309
|
+
let bodyText;
|
|
12310
|
+
try {
|
|
12311
|
+
bodyText = await response.text();
|
|
12312
|
+
} catch (cause) {
|
|
12313
|
+
const aborted = opts.signal?.aborted === true || typeof cause === "object" && cause !== null && cause.name === "AbortError";
|
|
12314
|
+
if (aborted) {
|
|
12315
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor3("cancelled", false), message: "attempt cancelled" });
|
|
12316
|
+
return;
|
|
12317
|
+
}
|
|
12318
|
+
yield errorEvent({
|
|
12319
|
+
kind: "malformed",
|
|
12320
|
+
retryable: retryableFor3("malformed", false),
|
|
12321
|
+
message: redact(`Gemini SSE body read failed: ${String(cause)}`)
|
|
12322
|
+
});
|
|
12323
|
+
return;
|
|
12324
|
+
}
|
|
12325
|
+
if (bodyText.length === 0) {
|
|
12326
|
+
yield errorEvent({
|
|
12327
|
+
kind: "malformed",
|
|
12328
|
+
retryable: retryableFor3("malformed", false),
|
|
12329
|
+
message: redact("empty response body")
|
|
12330
|
+
});
|
|
12331
|
+
return;
|
|
12332
|
+
}
|
|
12333
|
+
const parser = new AnthropicSSEParser;
|
|
12334
|
+
const records = parser.push(bodyText);
|
|
12335
|
+
const torn = parser.flush();
|
|
12336
|
+
const bodies = [];
|
|
12337
|
+
let sawFirstChunk = false;
|
|
12338
|
+
let sawFinish = false;
|
|
12339
|
+
let malformed;
|
|
12340
|
+
let promptTokens;
|
|
12341
|
+
let candidatesTokens;
|
|
12342
|
+
let totalTokens;
|
|
12343
|
+
let cachedContentTokens;
|
|
12344
|
+
let thoughtsTokens;
|
|
12345
|
+
for (const record of records) {
|
|
12346
|
+
let parsed;
|
|
12347
|
+
try {
|
|
12348
|
+
parsed = JSON.parse(record.data);
|
|
12349
|
+
} catch {
|
|
12350
|
+
malformed = {
|
|
12351
|
+
kind: "malformed",
|
|
12352
|
+
retryable: retryableFor3("malformed", false),
|
|
12353
|
+
message: redact("Gemini SSE data line was not valid JSON")
|
|
12354
|
+
};
|
|
12355
|
+
break;
|
|
12356
|
+
}
|
|
12357
|
+
const chunk = asRecord4(parsed);
|
|
12358
|
+
if (!sawFirstChunk) {
|
|
12359
|
+
sawFirstChunk = true;
|
|
12360
|
+
bodies.push({ kind: "model_start" });
|
|
12361
|
+
}
|
|
12362
|
+
const candidates = asArray2(chunk.candidates);
|
|
12363
|
+
const firstCandidate = asRecord4(candidates[0]);
|
|
12364
|
+
const content = asRecord4(firstCandidate.content);
|
|
12365
|
+
const parts = asArray2(content.parts);
|
|
12366
|
+
for (const rawPart of parts) {
|
|
12367
|
+
const part = asRecord4(rawPart);
|
|
12368
|
+
const text = asString4(part.text);
|
|
12369
|
+
if (text !== undefined) {
|
|
12370
|
+
if (asBoolean(part.thought)) {
|
|
12371
|
+
bodies.push({ kind: "reasoning_delta", text });
|
|
12372
|
+
} else {
|
|
12373
|
+
bodies.push({ kind: "text_delta", text });
|
|
12374
|
+
}
|
|
11737
12375
|
continue;
|
|
11738
12376
|
}
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
|
|
12377
|
+
const functionCall = asRecord4(part.functionCall);
|
|
12378
|
+
const callName = asString4(functionCall.name);
|
|
12379
|
+
if (callName !== undefined) {
|
|
12380
|
+
const callId = asString4(functionCall.id) ?? callName;
|
|
12381
|
+
const argsInput = JSON.stringify(asRecord4(functionCall.args));
|
|
12382
|
+
bodies.push({ kind: "tool_call_start", toolCallId: callId, toolName: callName });
|
|
12383
|
+
bodies.push({ kind: "tool_call_end", toolCallId: callId, input: argsInput });
|
|
12384
|
+
}
|
|
11742
12385
|
}
|
|
11743
|
-
|
|
12386
|
+
const usageMetadata = asRecord4(chunk.usageMetadata);
|
|
12387
|
+
if (Object.keys(usageMetadata).length > 0) {
|
|
12388
|
+
promptTokens = asNumber4(usageMetadata.promptTokenCount) ?? promptTokens;
|
|
12389
|
+
candidatesTokens = asNumber4(usageMetadata.candidatesTokenCount) ?? candidatesTokens;
|
|
12390
|
+
totalTokens = asNumber4(usageMetadata.totalTokenCount) ?? totalTokens;
|
|
12391
|
+
cachedContentTokens = asNumber4(usageMetadata.cachedContentTokenCount) ?? cachedContentTokens;
|
|
12392
|
+
thoughtsTokens = asNumber4(usageMetadata.thoughtsTokenCount) ?? thoughtsTokens;
|
|
12393
|
+
}
|
|
12394
|
+
const finishReason = asString4(firstCandidate.finishReason);
|
|
12395
|
+
if (finishReason !== undefined && finishReason.length > 0) {
|
|
12396
|
+
sawFinish = true;
|
|
12397
|
+
}
|
|
12398
|
+
}
|
|
12399
|
+
if (promptTokens !== undefined || candidatesTokens !== undefined || totalTokens !== undefined) {
|
|
12400
|
+
const usage = mergeUsage3(promptTokens, candidatesTokens, totalTokens);
|
|
12401
|
+
const unknownExtensions = {};
|
|
12402
|
+
if (cachedContentTokens !== undefined) {
|
|
12403
|
+
unknownExtensions["gemini.cached_content_tokens"] = cachedContentTokens;
|
|
12404
|
+
}
|
|
12405
|
+
if (thoughtsTokens !== undefined) {
|
|
12406
|
+
unknownExtensions["gemini.thoughts_tokens"] = thoughtsTokens;
|
|
12407
|
+
}
|
|
12408
|
+
bodies.push({
|
|
12409
|
+
kind: "usage_update",
|
|
12410
|
+
usage,
|
|
12411
|
+
...Object.keys(unknownExtensions).length > 0 ? { unknownExtensions } : {}
|
|
12412
|
+
});
|
|
12413
|
+
}
|
|
12414
|
+
if (sawFinish) {
|
|
12415
|
+
bodies.push({ kind: "model_end" });
|
|
12416
|
+
}
|
|
12417
|
+
if (malformed === undefined) {
|
|
12418
|
+
if (torn.length > 0) {
|
|
12419
|
+
malformed = {
|
|
12420
|
+
kind: "malformed",
|
|
12421
|
+
retryable: retryableFor3("malformed", false),
|
|
12422
|
+
message: redact("Gemini SSE stream ended mid-record (torn stream)")
|
|
12423
|
+
};
|
|
12424
|
+
} else if (sawFirstChunk && !sawFinish) {
|
|
12425
|
+
malformed = {
|
|
12426
|
+
kind: "malformed",
|
|
12427
|
+
retryable: retryableFor3("malformed", false),
|
|
12428
|
+
message: redact("Gemini SSE stream ended before a finishReason was reported (truncated stream)")
|
|
12429
|
+
};
|
|
12430
|
+
}
|
|
12431
|
+
}
|
|
12432
|
+
for (const body of bodies) {
|
|
12433
|
+
if (opts.signal?.aborted === true) {
|
|
12434
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor3("cancelled", false), message: "attempt cancelled" });
|
|
12435
|
+
return;
|
|
12436
|
+
}
|
|
12437
|
+
yield stamp(body);
|
|
12438
|
+
}
|
|
12439
|
+
if (opts.signal?.aborted === true) {
|
|
12440
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor3("cancelled", false), message: "attempt cancelled" });
|
|
12441
|
+
return;
|
|
12442
|
+
}
|
|
12443
|
+
if (malformed !== undefined) {
|
|
12444
|
+
yield stamp({ kind: "provider_error", error: malformed });
|
|
12445
|
+
}
|
|
12446
|
+
}
|
|
12447
|
+
}
|
|
12448
|
+
var DEFAULT_BASE_URL2 = "https://generativelanguage.googleapis.com", PROVIDER_REVISION2 = "gemini-2026-08-20", DEFAULT_MODEL2;
|
|
12449
|
+
var init_gemini_provider = __esm(() => {
|
|
12450
|
+
init_guard2();
|
|
12451
|
+
init_provider_port();
|
|
12452
|
+
DEFAULT_MODEL2 = {
|
|
12453
|
+
modelId: "gemini-2.5-flash",
|
|
12454
|
+
revision: "2.5"
|
|
12455
|
+
};
|
|
12456
|
+
});
|
|
12457
|
+
|
|
12458
|
+
// src/harness/provider/ollama/ollama-provider.ts
|
|
12459
|
+
class OllamaProvider {
|
|
12460
|
+
engine;
|
|
12461
|
+
constructor(deps) {
|
|
12462
|
+
this.engine = new OpenAiCompatEngine(deps, {
|
|
12463
|
+
defaultBaseUrl: DEFAULT_BASE_URL3,
|
|
12464
|
+
providerRevision: PROVIDER_REVISION3,
|
|
12465
|
+
providerId: "ollama",
|
|
12466
|
+
providerLabel: "Ollama",
|
|
12467
|
+
defaultModel: DEFAULT_MODEL3
|
|
12468
|
+
});
|
|
12469
|
+
}
|
|
12470
|
+
describe() {
|
|
12471
|
+
return this.engine.describe();
|
|
12472
|
+
}
|
|
12473
|
+
descriptorDocument() {
|
|
12474
|
+
return this.engine.descriptorDocument();
|
|
12475
|
+
}
|
|
12476
|
+
stream(request, opts) {
|
|
12477
|
+
return this.engine.stream(request, opts);
|
|
12478
|
+
}
|
|
12479
|
+
}
|
|
12480
|
+
var DEFAULT_BASE_URL3 = "http://localhost:11434", PROVIDER_REVISION3 = "ollama-2024-10-22", DEFAULT_MODEL3;
|
|
12481
|
+
var init_ollama_provider = __esm(() => {
|
|
12482
|
+
init_openai_compat_provider();
|
|
12483
|
+
DEFAULT_MODEL3 = {
|
|
12484
|
+
modelId: "llama3.1:latest",
|
|
12485
|
+
revision: "latest"
|
|
12486
|
+
};
|
|
12487
|
+
});
|
|
12488
|
+
|
|
12489
|
+
// src/harness/provider/openai/openai-provider.ts
|
|
12490
|
+
function isPlainObject7(value) {
|
|
12491
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12492
|
+
}
|
|
12493
|
+
function asRecord5(value) {
|
|
12494
|
+
return isPlainObject7(value) ? value : {};
|
|
12495
|
+
}
|
|
12496
|
+
function asString5(value) {
|
|
12497
|
+
return typeof value === "string" ? value : undefined;
|
|
12498
|
+
}
|
|
12499
|
+
function asNumber5(value) {
|
|
12500
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
12501
|
+
}
|
|
12502
|
+
function toResponsesInput(messages) {
|
|
12503
|
+
const out = [];
|
|
12504
|
+
for (const linked of linkToolCalls(messages)) {
|
|
12505
|
+
const message = linked.message;
|
|
12506
|
+
if (message.role === "tool") {
|
|
12507
|
+
if (linked.linkedToolCallId !== undefined) {
|
|
12508
|
+
out.push({ type: "function_call_output", call_id: linked.linkedToolCallId, output: message.content });
|
|
11744
12509
|
continue;
|
|
11745
12510
|
}
|
|
11746
|
-
|
|
11747
|
-
|
|
12511
|
+
out.push({ type: "message", role: "user", content: [{ type: "input_text", text: message.content }] });
|
|
12512
|
+
continue;
|
|
12513
|
+
}
|
|
12514
|
+
if (message.role === "assistant" && message.content.length === 0 && linked.linkedCalls.length === 0) {
|
|
12515
|
+
continue;
|
|
12516
|
+
}
|
|
12517
|
+
if (message.role === "assistant" && linked.linkedCalls.length > 0) {
|
|
12518
|
+
if (message.content.length > 0) {
|
|
12519
|
+
out.push({
|
|
12520
|
+
type: "message",
|
|
11748
12521
|
role: "assistant",
|
|
11749
|
-
content: message.content
|
|
11750
|
-
tool_calls: linked.linkedCalls.map((call) => ({
|
|
11751
|
-
id: call.id,
|
|
11752
|
-
type: "function",
|
|
11753
|
-
function: { name: call.name, arguments: call.arguments }
|
|
11754
|
-
}))
|
|
12522
|
+
content: [{ type: "output_text", text: message.content }]
|
|
11755
12523
|
});
|
|
11756
|
-
continue;
|
|
11757
12524
|
}
|
|
11758
|
-
|
|
12525
|
+
for (const call of linked.linkedCalls) {
|
|
12526
|
+
out.push({ type: "function_call", call_id: call.id, name: call.name, arguments: call.arguments });
|
|
12527
|
+
}
|
|
12528
|
+
continue;
|
|
12529
|
+
}
|
|
12530
|
+
out.push({
|
|
12531
|
+
type: "message",
|
|
12532
|
+
role: message.role === "assistant" ? "assistant" : "user",
|
|
12533
|
+
content: [{ type: message.role === "assistant" ? "output_text" : "input_text", text: message.content }]
|
|
12534
|
+
});
|
|
12535
|
+
}
|
|
12536
|
+
return out;
|
|
12537
|
+
}
|
|
12538
|
+
function retryableFor4(kind, fallback) {
|
|
12539
|
+
const concrete = defaultRetryable(kind);
|
|
12540
|
+
return concrete === undefined ? fallback : concrete;
|
|
12541
|
+
}
|
|
12542
|
+
function mergeUsage4(inputTokens, outputTokens, totalTokens) {
|
|
12543
|
+
const usage = { exact: true };
|
|
12544
|
+
if (inputTokens !== undefined) {
|
|
12545
|
+
usage.inputTokens = inputTokens;
|
|
12546
|
+
}
|
|
12547
|
+
if (outputTokens !== undefined) {
|
|
12548
|
+
usage.outputTokens = outputTokens;
|
|
12549
|
+
}
|
|
12550
|
+
if (totalTokens !== undefined) {
|
|
12551
|
+
usage.totalTokens = totalTokens;
|
|
12552
|
+
} else if (inputTokens !== undefined || outputTokens !== undefined) {
|
|
12553
|
+
usage.totalTokens = (inputTokens ?? 0) + (outputTokens ?? 0);
|
|
12554
|
+
}
|
|
12555
|
+
return usage;
|
|
12556
|
+
}
|
|
12557
|
+
function extractErrorFields(data) {
|
|
12558
|
+
const nested = asRecord5(data.error);
|
|
12559
|
+
const code = asString5(nested.code) ?? asString5(data.code);
|
|
12560
|
+
const message = asString5(nested.message) ?? asString5(data.message);
|
|
12561
|
+
const param = asString5(nested.param) ?? asString5(data.param);
|
|
12562
|
+
const out = {};
|
|
12563
|
+
if (code !== undefined) {
|
|
12564
|
+
out.code = code;
|
|
12565
|
+
}
|
|
12566
|
+
if (message !== undefined) {
|
|
12567
|
+
out.message = message;
|
|
12568
|
+
}
|
|
12569
|
+
if (param !== undefined) {
|
|
12570
|
+
out.param = param;
|
|
12571
|
+
}
|
|
12572
|
+
return out;
|
|
12573
|
+
}
|
|
12574
|
+
function classifyHttpError3(status, headers, code) {
|
|
12575
|
+
if (status === 401) {
|
|
12576
|
+
return { kind: "authentication", retryable: retryableFor4("authentication", false), message: "" };
|
|
12577
|
+
}
|
|
12578
|
+
if (status === 429) {
|
|
12579
|
+
const error = { kind: "rate_limit", retryable: retryableFor4("rate_limit", true), message: "" };
|
|
12580
|
+
const retryAfter = headers.get("retry-after");
|
|
12581
|
+
const seconds = retryAfter === null ? undefined : Number.parseInt(retryAfter, 10);
|
|
12582
|
+
if (seconds !== undefined && Number.isFinite(seconds)) {
|
|
12583
|
+
error.retryAfterMs = seconds * 1000;
|
|
12584
|
+
}
|
|
12585
|
+
return error;
|
|
12586
|
+
}
|
|
12587
|
+
if (status === 400) {
|
|
12588
|
+
if (code === "context_length_exceeded") {
|
|
12589
|
+
return { kind: "context_overflow", retryable: retryableFor4("context_overflow", false), message: "" };
|
|
12590
|
+
}
|
|
12591
|
+
return { kind: "invalid_request", retryable: retryableFor4("invalid_request", false), message: "" };
|
|
12592
|
+
}
|
|
12593
|
+
if (status >= 500) {
|
|
12594
|
+
return { kind: "unavailable", retryable: retryableFor4("unavailable", true), message: "" };
|
|
12595
|
+
}
|
|
12596
|
+
if (status >= 400) {
|
|
12597
|
+
return { kind: "invalid_request", retryable: retryableFor4("invalid_request", false), message: "" };
|
|
12598
|
+
}
|
|
12599
|
+
return { kind: "unknown", retryable: retryableFor4("unknown", false), message: "" };
|
|
12600
|
+
}
|
|
12601
|
+
|
|
12602
|
+
class OpenAiProvider {
|
|
12603
|
+
deps;
|
|
12604
|
+
constructor(deps) {
|
|
12605
|
+
this.deps = deps;
|
|
12606
|
+
}
|
|
12607
|
+
describe() {
|
|
12608
|
+
const capabilities = {
|
|
12609
|
+
streaming: true,
|
|
12610
|
+
toolCalls: true,
|
|
12611
|
+
parallelToolCalls: true,
|
|
12612
|
+
structuredOutput: true,
|
|
12613
|
+
reasoningMetadata: true,
|
|
12614
|
+
promptCaching: true,
|
|
12615
|
+
vision: false,
|
|
12616
|
+
tokenCounting: false,
|
|
12617
|
+
modelListing: false
|
|
12618
|
+
};
|
|
12619
|
+
return {
|
|
12620
|
+
capabilities,
|
|
12621
|
+
descriptor: { providerId: "openai", providerRevision: PROVIDER_REVISION4 }
|
|
12622
|
+
};
|
|
12623
|
+
}
|
|
12624
|
+
descriptorDocument() {
|
|
12625
|
+
return {
|
|
12626
|
+
schemaVersion: 1,
|
|
12627
|
+
providerId: "openai",
|
|
12628
|
+
providerRevision: PROVIDER_REVISION4,
|
|
12629
|
+
models: [{ modelId: DEFAULT_MODEL4.modelId, revision: DEFAULT_MODEL4.revision }],
|
|
12630
|
+
capabilities: {
|
|
12631
|
+
streaming: true,
|
|
12632
|
+
tools: true,
|
|
12633
|
+
parallelToolCalls: true,
|
|
12634
|
+
cancellation: true,
|
|
12635
|
+
structuredOutput: true
|
|
12636
|
+
},
|
|
12637
|
+
remoteState: { storage: false, retention: false, continuation: false }
|
|
12638
|
+
};
|
|
12639
|
+
}
|
|
12640
|
+
async* stream(request, opts) {
|
|
12641
|
+
let sequence = 0;
|
|
12642
|
+
const stamp = (body) => ({ ...body, sequence: sequence++, attemptId: opts.attemptId });
|
|
12643
|
+
const errorEvent = (error) => stamp({ kind: "provider_error", error });
|
|
12644
|
+
const grant = this.deps.grant;
|
|
12645
|
+
const redact = (message) => grant !== undefined && grant.apiKey.length > 0 ? message.split(grant.apiKey).join("[redacted]") : message;
|
|
12646
|
+
if (grant === undefined || grant.network !== true || typeof grant.apiKey !== "string" || grant.apiKey.length === 0) {
|
|
12647
|
+
yield errorEvent({
|
|
12648
|
+
kind: "authentication",
|
|
12649
|
+
retryable: retryableFor4("authentication", false),
|
|
12650
|
+
message: "network capability grant with an apiKey is required to reach the OpenAI API"
|
|
12651
|
+
});
|
|
12652
|
+
return;
|
|
11759
12653
|
}
|
|
12654
|
+
const baseUrl = grant.baseUrl ?? DEFAULT_BASE_URL4;
|
|
12655
|
+
let host;
|
|
12656
|
+
try {
|
|
12657
|
+
host = new URL(baseUrl).hostname;
|
|
12658
|
+
} catch {
|
|
12659
|
+
host = baseUrl;
|
|
12660
|
+
}
|
|
12661
|
+
if (isPrivateEgressHost(host)) {
|
|
12662
|
+
yield errorEvent({
|
|
12663
|
+
kind: "invalid_request",
|
|
12664
|
+
retryable: retryableFor4("invalid_request", false),
|
|
12665
|
+
message: redact(`egress to a private/loopback/link-local/metadata host is denied: ${host}`)
|
|
12666
|
+
});
|
|
12667
|
+
return;
|
|
12668
|
+
}
|
|
12669
|
+
const url = `${baseUrl.replace(/\/+$/, "")}/v1/responses`;
|
|
12670
|
+
const headers = {
|
|
12671
|
+
authorization: `Bearer ${grant.apiKey}`,
|
|
12672
|
+
"content-type": "application/json"
|
|
12673
|
+
};
|
|
11760
12674
|
const payload = {
|
|
11761
12675
|
model: request.modelId,
|
|
12676
|
+
instructions: request.systemInstruction,
|
|
12677
|
+
input: toResponsesInput(request.messages),
|
|
11762
12678
|
stream: true,
|
|
11763
|
-
messages,
|
|
11764
12679
|
...request.tools !== undefined ? {
|
|
11765
12680
|
tools: request.tools.map((tool) => ({
|
|
11766
12681
|
type: "function",
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
}))
|
|
12682
|
+
name: tool.name,
|
|
12683
|
+
...tool.description !== undefined ? { description: tool.description } : {},
|
|
12684
|
+
parameters: tool.inputSchema
|
|
12685
|
+
})),
|
|
12686
|
+
parallel_tool_calls: true
|
|
11773
12687
|
} : {}
|
|
11774
12688
|
};
|
|
11775
|
-
const headers = { "content-type": "application/json" };
|
|
11776
|
-
if (grant.apiKey !== undefined && grant.apiKey.length > 0) {
|
|
11777
|
-
headers.authorization = `Bearer ${grant.apiKey}`;
|
|
11778
|
-
}
|
|
11779
|
-
if (grant.headers !== undefined) {
|
|
11780
|
-
Object.assign(headers, grant.headers);
|
|
11781
|
-
}
|
|
11782
12689
|
const init = {
|
|
11783
12690
|
method: "POST",
|
|
11784
12691
|
headers,
|
|
@@ -11790,27 +12697,28 @@ ${message.content}` });
|
|
|
11790
12697
|
response = await this.deps.fetch(url, init);
|
|
11791
12698
|
} catch (cause) {
|
|
11792
12699
|
if (opts.signal?.aborted === true) {
|
|
11793
|
-
yield errorEvent({ kind: "cancelled", retryable:
|
|
12700
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor4("cancelled", false), message: "attempt cancelled" });
|
|
11794
12701
|
return;
|
|
11795
12702
|
}
|
|
11796
12703
|
yield errorEvent({
|
|
11797
12704
|
kind: "unavailable",
|
|
11798
|
-
retryable:
|
|
11799
|
-
message: `network request to the
|
|
12705
|
+
retryable: retryableFor4("unavailable", true),
|
|
12706
|
+
message: redact(`network request to the OpenAI API failed: ${String(cause)}`)
|
|
11800
12707
|
});
|
|
11801
12708
|
return;
|
|
11802
12709
|
}
|
|
11803
12710
|
if (!response.ok) {
|
|
11804
|
-
|
|
11805
|
-
let providerMessage = `Ollama API returned HTTP ${response.status}`;
|
|
12711
|
+
let bodyRecord = {};
|
|
11806
12712
|
try {
|
|
11807
|
-
|
|
11808
|
-
const detail = asString3(asRecord3(parsed.error).message);
|
|
11809
|
-
if (detail !== undefined && detail.length > 0) {
|
|
11810
|
-
providerMessage = detail;
|
|
11811
|
-
}
|
|
12713
|
+
bodyRecord = asRecord5(JSON.parse(await response.text()));
|
|
11812
12714
|
} catch {}
|
|
11813
|
-
|
|
12715
|
+
const fields = extractErrorFields(bodyRecord);
|
|
12716
|
+
const error = classifyHttpError3(response.status, response.headers, fields.code);
|
|
12717
|
+
let providerMessage = `OpenAI API returned HTTP ${response.status}`;
|
|
12718
|
+
if (fields.message !== undefined && fields.message.length > 0) {
|
|
12719
|
+
providerMessage = fields.message;
|
|
12720
|
+
}
|
|
12721
|
+
error.message = redact(providerMessage);
|
|
11814
12722
|
yield stamp({ kind: "provider_error", error });
|
|
11815
12723
|
return;
|
|
11816
12724
|
}
|
|
@@ -11820,21 +12728,21 @@ ${message.content}` });
|
|
|
11820
12728
|
} catch (cause) {
|
|
11821
12729
|
const aborted = opts.signal?.aborted === true || typeof cause === "object" && cause !== null && cause.name === "AbortError";
|
|
11822
12730
|
if (aborted) {
|
|
11823
|
-
yield errorEvent({ kind: "cancelled", retryable:
|
|
12731
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor4("cancelled", false), message: "attempt cancelled" });
|
|
11824
12732
|
return;
|
|
11825
12733
|
}
|
|
11826
12734
|
yield errorEvent({
|
|
11827
12735
|
kind: "malformed",
|
|
11828
|
-
retryable:
|
|
11829
|
-
message: `
|
|
12736
|
+
retryable: retryableFor4("malformed", false),
|
|
12737
|
+
message: redact(`OpenAI SSE body read failed: ${String(cause)}`)
|
|
11830
12738
|
});
|
|
11831
12739
|
return;
|
|
11832
12740
|
}
|
|
11833
12741
|
if (bodyText.length === 0) {
|
|
11834
12742
|
yield errorEvent({
|
|
11835
12743
|
kind: "malformed",
|
|
11836
|
-
retryable:
|
|
11837
|
-
message: "empty response body"
|
|
12744
|
+
retryable: retryableFor4("malformed", false),
|
|
12745
|
+
message: redact("empty response body")
|
|
11838
12746
|
});
|
|
11839
12747
|
return;
|
|
11840
12748
|
}
|
|
@@ -11842,149 +12750,193 @@ ${message.content}` });
|
|
|
11842
12750
|
const records = parser.push(bodyText);
|
|
11843
12751
|
const torn = parser.flush();
|
|
11844
12752
|
const bodies = [];
|
|
12753
|
+
const pendingTools = new Map;
|
|
11845
12754
|
let sawStart = false;
|
|
11846
|
-
let
|
|
11847
|
-
let sawDone = false;
|
|
12755
|
+
let sawCompleted = false;
|
|
11848
12756
|
let malformed;
|
|
11849
|
-
|
|
11850
|
-
const toolCallKey = (toolCall) => {
|
|
11851
|
-
const index = asNumber3(toolCall.index);
|
|
11852
|
-
if (index !== undefined) {
|
|
11853
|
-
return `idx:${index}`;
|
|
11854
|
-
}
|
|
11855
|
-
const id = asString3(toolCall.id);
|
|
11856
|
-
if (id !== undefined && id.length > 0) {
|
|
11857
|
-
return `id:${id}`;
|
|
11858
|
-
}
|
|
11859
|
-
return "idx:0";
|
|
11860
|
-
};
|
|
11861
|
-
const flushPendingToolEnds = () => {
|
|
11862
|
-
for (const acc of pendingTools.values()) {
|
|
11863
|
-
if (acc.ended) {
|
|
11864
|
-
continue;
|
|
11865
|
-
}
|
|
11866
|
-
if (!acc.started) {
|
|
11867
|
-
const startBody = { kind: "tool_call_start", toolCallId: acc.id };
|
|
11868
|
-
if (acc.name.length > 0) {
|
|
11869
|
-
startBody.toolName = acc.name;
|
|
11870
|
-
}
|
|
11871
|
-
bodies.push(startBody);
|
|
11872
|
-
acc.started = true;
|
|
11873
|
-
}
|
|
11874
|
-
bodies.push({ kind: "tool_call_end", toolCallId: acc.id, input: acc.arguments });
|
|
11875
|
-
acc.ended = true;
|
|
11876
|
-
}
|
|
11877
|
-
pendingTools.clear();
|
|
11878
|
-
};
|
|
12757
|
+
let terminalError;
|
|
11879
12758
|
for (const record of records) {
|
|
11880
|
-
const trimmed = record.data.trim();
|
|
11881
|
-
if (trimmed === "[DONE]") {
|
|
11882
|
-
sawDone = true;
|
|
11883
|
-
flushPendingToolEnds();
|
|
11884
|
-
continue;
|
|
11885
|
-
}
|
|
11886
|
-
if (!sawStart) {
|
|
11887
|
-
sawStart = true;
|
|
11888
|
-
bodies.push({ kind: "model_start" });
|
|
11889
|
-
}
|
|
11890
12759
|
let parsed;
|
|
11891
12760
|
try {
|
|
11892
12761
|
parsed = JSON.parse(record.data);
|
|
11893
12762
|
} catch {
|
|
11894
12763
|
malformed = {
|
|
11895
12764
|
kind: "malformed",
|
|
11896
|
-
retryable:
|
|
11897
|
-
message: "
|
|
12765
|
+
retryable: retryableFor4("malformed", false),
|
|
12766
|
+
message: redact("OpenAI SSE data line was not valid JSON")
|
|
11898
12767
|
};
|
|
11899
12768
|
break;
|
|
11900
12769
|
}
|
|
11901
|
-
const data =
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
usage: mergeUsage2(asNumber3(usage.prompt_tokens), asNumber3(usage.completion_tokens), asNumber3(usage.total_tokens))
|
|
11907
|
-
});
|
|
11908
|
-
}
|
|
11909
|
-
const choice0 = asRecord3(asArray(data.choices)[0]);
|
|
11910
|
-
const delta = asRecord3(choice0.delta);
|
|
11911
|
-
const reasoning = asString3(delta.reasoning) ?? asString3(delta.reasoning_content);
|
|
11912
|
-
if (reasoning !== undefined && reasoning.length > 0) {
|
|
11913
|
-
bodies.push({ kind: "reasoning_delta", text: reasoning });
|
|
11914
|
-
}
|
|
11915
|
-
const content = asString3(delta.content);
|
|
11916
|
-
if (content !== undefined && content.length > 0) {
|
|
11917
|
-
bodies.push({ kind: "text_delta", text: content });
|
|
11918
|
-
}
|
|
11919
|
-
for (const rawToolCall of asArray(delta.tool_calls)) {
|
|
11920
|
-
const toolCall = asRecord3(rawToolCall);
|
|
11921
|
-
const fn = asRecord3(toolCall.function);
|
|
11922
|
-
const toolCallId = asString3(toolCall.id);
|
|
11923
|
-
const toolName = asString3(fn.name);
|
|
11924
|
-
const argumentsFragment = asString3(fn.arguments) ?? "";
|
|
11925
|
-
const key = toolCallKey(toolCall);
|
|
11926
|
-
let acc = pendingTools.get(key);
|
|
11927
|
-
if (acc === undefined) {
|
|
11928
|
-
acc = {
|
|
11929
|
-
id: toolCallId ?? `call_${key.replace(/[^a-zA-Z0-9_:-]/g, "_")}`,
|
|
11930
|
-
name: toolName ?? "",
|
|
11931
|
-
arguments: "",
|
|
11932
|
-
started: false,
|
|
11933
|
-
ended: false
|
|
11934
|
-
};
|
|
11935
|
-
pendingTools.set(key, acc);
|
|
12770
|
+
const data = asRecord5(parsed);
|
|
12771
|
+
const eventType = asString5(data.type) ?? asString5(record.event);
|
|
12772
|
+
switch (eventType) {
|
|
12773
|
+
case "response.created": {
|
|
12774
|
+
break;
|
|
11936
12775
|
}
|
|
11937
|
-
|
|
11938
|
-
|
|
12776
|
+
case "response.output_item.added": {
|
|
12777
|
+
const item = asRecord5(data.item);
|
|
12778
|
+
if (asString5(item.type) === "function_call") {
|
|
12779
|
+
if (!sawStart) {
|
|
12780
|
+
sawStart = true;
|
|
12781
|
+
bodies.push({ kind: "model_start" });
|
|
12782
|
+
}
|
|
12783
|
+
const itemId = asString5(data.item_id) ?? asString5(item.id) ?? "";
|
|
12784
|
+
const callId = asString5(item.call_id) ?? itemId;
|
|
12785
|
+
const toolName = asString5(item.name);
|
|
12786
|
+
pendingTools.set(itemId, { callId, name: toolName ?? "", arguments: asString5(item.arguments) ?? "" });
|
|
12787
|
+
const startBody = { kind: "tool_call_start", toolCallId: callId };
|
|
12788
|
+
if (toolName !== undefined) {
|
|
12789
|
+
startBody.toolName = toolName;
|
|
12790
|
+
}
|
|
12791
|
+
bodies.push(startBody);
|
|
12792
|
+
}
|
|
12793
|
+
break;
|
|
11939
12794
|
}
|
|
11940
|
-
|
|
11941
|
-
|
|
12795
|
+
case "response.output_text.delta": {
|
|
12796
|
+
if (!sawStart) {
|
|
12797
|
+
sawStart = true;
|
|
12798
|
+
bodies.push({ kind: "model_start" });
|
|
12799
|
+
}
|
|
12800
|
+
const text = asString5(data.delta);
|
|
12801
|
+
const body = { kind: "text_delta" };
|
|
12802
|
+
if (text !== undefined) {
|
|
12803
|
+
body.text = text;
|
|
12804
|
+
}
|
|
12805
|
+
bodies.push(body);
|
|
12806
|
+
break;
|
|
11942
12807
|
}
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
12808
|
+
case "response.reasoning_summary_text.delta": {
|
|
12809
|
+
if (!sawStart) {
|
|
12810
|
+
sawStart = true;
|
|
12811
|
+
bodies.push({ kind: "model_start" });
|
|
11947
12812
|
}
|
|
11948
|
-
|
|
11949
|
-
|
|
12813
|
+
const text = asString5(data.delta);
|
|
12814
|
+
if (text !== undefined && text.length > 0) {
|
|
12815
|
+
bodies.push({ kind: "reasoning_delta", text });
|
|
12816
|
+
}
|
|
12817
|
+
break;
|
|
11950
12818
|
}
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
12819
|
+
case "response.function_call_arguments.delta": {
|
|
12820
|
+
const itemId = asString5(data.item_id) ?? "";
|
|
12821
|
+
const fragment = asString5(data.delta) ?? "";
|
|
12822
|
+
const pending = pendingTools.get(itemId);
|
|
12823
|
+
const toolCallId = pending?.callId ?? itemId;
|
|
12824
|
+
if (pending !== undefined) {
|
|
12825
|
+
pending.arguments += fragment;
|
|
12826
|
+
}
|
|
12827
|
+
if (fragment.length > 0) {
|
|
12828
|
+
bodies.push({ kind: "tool_call_delta", toolCallId, inputDelta: fragment });
|
|
12829
|
+
}
|
|
12830
|
+
break;
|
|
12831
|
+
}
|
|
12832
|
+
case "response.function_call_arguments.done": {
|
|
12833
|
+
const itemId = asString5(data.item_id) ?? "";
|
|
12834
|
+
const pending = pendingTools.get(itemId);
|
|
12835
|
+
const fullArguments = asString5(data.arguments) ?? pending?.arguments ?? "";
|
|
12836
|
+
const toolCallId = pending?.callId ?? itemId;
|
|
12837
|
+
bodies.push({ kind: "tool_call_end", toolCallId, input: fullArguments });
|
|
12838
|
+
pendingTools.delete(itemId);
|
|
12839
|
+
break;
|
|
12840
|
+
}
|
|
12841
|
+
case "response.output_item.done": {
|
|
12842
|
+
const item = asRecord5(data.item);
|
|
12843
|
+
if (asString5(item.type) === "function_call") {
|
|
12844
|
+
const itemId = asString5(data.item_id) ?? asString5(item.id) ?? "";
|
|
12845
|
+
const pending = pendingTools.get(itemId);
|
|
12846
|
+
if (pending !== undefined) {
|
|
12847
|
+
const fullArguments = asString5(item.arguments) ?? pending.arguments;
|
|
12848
|
+
bodies.push({ kind: "tool_call_end", toolCallId: pending.callId, input: fullArguments });
|
|
12849
|
+
pendingTools.delete(itemId);
|
|
12850
|
+
}
|
|
12851
|
+
}
|
|
12852
|
+
break;
|
|
12853
|
+
}
|
|
12854
|
+
case "response.completed": {
|
|
12855
|
+
sawCompleted = true;
|
|
12856
|
+
const usage = asRecord5(asRecord5(data.response).usage);
|
|
12857
|
+
const inputTokens = asNumber5(usage.input_tokens);
|
|
12858
|
+
const outputTokens = asNumber5(usage.output_tokens);
|
|
12859
|
+
const totalTokens = asNumber5(usage.total_tokens);
|
|
12860
|
+
const reasoningTokens = asNumber5(asRecord5(usage.output_tokens_details).reasoning_tokens);
|
|
12861
|
+
const usageBody = {
|
|
12862
|
+
kind: "usage_update",
|
|
12863
|
+
usage: mergeUsage4(inputTokens, outputTokens, totalTokens)
|
|
12864
|
+
};
|
|
12865
|
+
if (reasoningTokens !== undefined) {
|
|
12866
|
+
usageBody.unknownExtensions = { "openai.reasoning_tokens": reasoningTokens };
|
|
12867
|
+
}
|
|
12868
|
+
bodies.push(usageBody);
|
|
12869
|
+
bodies.push({ kind: "model_end" });
|
|
12870
|
+
break;
|
|
12871
|
+
}
|
|
12872
|
+
case "response.failed":
|
|
12873
|
+
case "response.incomplete": {
|
|
12874
|
+
const fields = extractErrorFields(asRecord5(data.response));
|
|
12875
|
+
const code = fields.code;
|
|
12876
|
+
let kind = "unknown";
|
|
12877
|
+
if (code === "context_length_exceeded") {
|
|
12878
|
+
kind = "context_overflow";
|
|
12879
|
+
} else if (code !== undefined && code.length > 0) {
|
|
12880
|
+
kind = "invalid_request";
|
|
12881
|
+
}
|
|
12882
|
+
let message = fields.message;
|
|
12883
|
+
if (message === undefined || message.length === 0) {
|
|
12884
|
+
message = kind === "context_overflow" ? "OpenAI Responses API returned an error with no message; likely context-length overflow" : "OpenAI Responses API returned an error with no message";
|
|
12885
|
+
}
|
|
12886
|
+
terminalError = { kind, retryable: retryableFor4(kind, false), message: redact(message) };
|
|
12887
|
+
break;
|
|
11958
12888
|
}
|
|
12889
|
+
case "error": {
|
|
12890
|
+
const fields = extractErrorFields(data);
|
|
12891
|
+
const code = fields.code;
|
|
12892
|
+
let kind = "unknown";
|
|
12893
|
+
if (code === "context_length_exceeded") {
|
|
12894
|
+
kind = "context_overflow";
|
|
12895
|
+
} else if (code !== undefined && code.length > 0) {
|
|
12896
|
+
kind = "invalid_request";
|
|
12897
|
+
}
|
|
12898
|
+
let message = fields.message;
|
|
12899
|
+
if (message === undefined || message.length === 0) {
|
|
12900
|
+
message = kind === "context_overflow" ? "OpenAI Responses API returned an error with no message; likely context-length overflow" : "OpenAI Responses API returned an error with no message; likely context-length overflow (unconfirmed cause)";
|
|
12901
|
+
}
|
|
12902
|
+
terminalError = { kind, retryable: retryableFor4(kind, false), message: redact(message) };
|
|
12903
|
+
break;
|
|
12904
|
+
}
|
|
12905
|
+
default:
|
|
12906
|
+
break;
|
|
11959
12907
|
}
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
sawFinish = true;
|
|
11963
|
-
flushPendingToolEnds();
|
|
12908
|
+
if (terminalError !== undefined) {
|
|
12909
|
+
break;
|
|
11964
12910
|
}
|
|
11965
12911
|
}
|
|
11966
|
-
if (malformed === undefined &&
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
12912
|
+
if (malformed === undefined && terminalError === undefined) {
|
|
12913
|
+
if (torn.length > 0) {
|
|
12914
|
+
malformed = {
|
|
12915
|
+
kind: "malformed",
|
|
12916
|
+
retryable: retryableFor4("malformed", false),
|
|
12917
|
+
message: redact("OpenAI SSE stream ended mid-record (torn stream)")
|
|
12918
|
+
};
|
|
12919
|
+
} else if (sawStart && !sawCompleted) {
|
|
12920
|
+
malformed = {
|
|
12921
|
+
kind: "malformed",
|
|
12922
|
+
retryable: retryableFor4("malformed", false),
|
|
12923
|
+
message: redact("OpenAI SSE stream ended before response.completed (truncated stream)")
|
|
12924
|
+
};
|
|
12925
|
+
}
|
|
11978
12926
|
}
|
|
11979
12927
|
for (const body of bodies) {
|
|
11980
12928
|
if (opts.signal?.aborted === true) {
|
|
11981
|
-
yield errorEvent({ kind: "cancelled", retryable:
|
|
12929
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor4("cancelled", false), message: "attempt cancelled" });
|
|
11982
12930
|
return;
|
|
11983
12931
|
}
|
|
11984
12932
|
yield stamp(body);
|
|
11985
12933
|
}
|
|
11986
12934
|
if (opts.signal?.aborted === true) {
|
|
11987
|
-
yield errorEvent({ kind: "cancelled", retryable:
|
|
12935
|
+
yield errorEvent({ kind: "cancelled", retryable: retryableFor4("cancelled", false), message: "attempt cancelled" });
|
|
12936
|
+
return;
|
|
12937
|
+
}
|
|
12938
|
+
if (terminalError !== undefined) {
|
|
12939
|
+
yield stamp({ kind: "provider_error", error: terminalError });
|
|
11988
12940
|
return;
|
|
11989
12941
|
}
|
|
11990
12942
|
if (malformed !== undefined) {
|
|
@@ -11992,13 +12944,13 @@ ${message.content}` });
|
|
|
11992
12944
|
}
|
|
11993
12945
|
}
|
|
11994
12946
|
}
|
|
11995
|
-
var
|
|
11996
|
-
var
|
|
12947
|
+
var DEFAULT_BASE_URL4 = "https://api.openai.com", PROVIDER_REVISION4 = "openai-responses-2026-08", DEFAULT_MODEL4;
|
|
12948
|
+
var init_openai_provider = __esm(() => {
|
|
11997
12949
|
init_guard2();
|
|
11998
12950
|
init_provider_port();
|
|
11999
|
-
|
|
12000
|
-
modelId: "
|
|
12001
|
-
revision: "
|
|
12951
|
+
DEFAULT_MODEL4 = {
|
|
12952
|
+
modelId: "gpt-4.1",
|
|
12953
|
+
revision: "2026-08"
|
|
12002
12954
|
};
|
|
12003
12955
|
});
|
|
12004
12956
|
|
|
@@ -12012,6 +12964,20 @@ function makeProvider(name, _model, opts) {
|
|
|
12012
12964
|
}
|
|
12013
12965
|
return new AnthropicProvider({ fetch: opts.fetch, grant: { network: true, apiKey } });
|
|
12014
12966
|
}
|
|
12967
|
+
if (name === "openai") {
|
|
12968
|
+
const apiKey = env.OPENAI_API_KEY;
|
|
12969
|
+
if (apiKey === undefined || apiKey.length === 0) {
|
|
12970
|
+
return new FakeProvider([]);
|
|
12971
|
+
}
|
|
12972
|
+
return new OpenAiProvider({ fetch: opts.fetch, grant: { network: true, apiKey } });
|
|
12973
|
+
}
|
|
12974
|
+
if (name === "gemini") {
|
|
12975
|
+
const apiKey = env.GEMINI_API_KEY !== undefined && env.GEMINI_API_KEY.length > 0 ? env.GEMINI_API_KEY : env.GOOGLE_API_KEY;
|
|
12976
|
+
if (apiKey === undefined || apiKey.length === 0) {
|
|
12977
|
+
return new FakeProvider([]);
|
|
12978
|
+
}
|
|
12979
|
+
return new GeminiProvider({ fetch: opts.fetch, grant: { network: true, apiKey } });
|
|
12980
|
+
}
|
|
12015
12981
|
if (name === "ollama") {
|
|
12016
12982
|
return new OllamaProvider({
|
|
12017
12983
|
fetch: opts.fetch,
|
|
@@ -12032,18 +12998,26 @@ function makeProvider(name, _model, opts) {
|
|
|
12032
12998
|
...compat.chatPath !== undefined ? { chatPath: compat.chatPath } : {},
|
|
12033
12999
|
...apiKey !== undefined ? { apiKey } : {}
|
|
12034
13000
|
};
|
|
12035
|
-
return new
|
|
12036
|
-
fetch: opts.fetch,
|
|
12037
|
-
grant
|
|
12038
|
-
});
|
|
13001
|
+
return new OpenAiCompatEngine({ fetch: opts.fetch, grant }, OLLAMA_COMPAT_IDENTITY);
|
|
12039
13002
|
}
|
|
12040
13003
|
return new FakeProvider([]);
|
|
12041
13004
|
}
|
|
13005
|
+
var OLLAMA_COMPAT_IDENTITY;
|
|
12042
13006
|
var init_make_provider = __esm(() => {
|
|
12043
13007
|
init_providers();
|
|
12044
13008
|
init_anthropic_provider();
|
|
13009
|
+
init_openai_compat_provider();
|
|
12045
13010
|
init_fake_provider();
|
|
13011
|
+
init_gemini_provider();
|
|
12046
13012
|
init_ollama_provider();
|
|
13013
|
+
init_openai_provider();
|
|
13014
|
+
OLLAMA_COMPAT_IDENTITY = {
|
|
13015
|
+
defaultBaseUrl: "http://localhost:11434",
|
|
13016
|
+
providerRevision: "ollama-2024-10-22",
|
|
13017
|
+
providerId: "ollama",
|
|
13018
|
+
providerLabel: "Ollama",
|
|
13019
|
+
defaultModel: { modelId: "llama3.1:latest", revision: "latest" }
|
|
13020
|
+
};
|
|
12047
13021
|
});
|
|
12048
13022
|
|
|
12049
13023
|
// src/harness/provider/single-turn.ts
|
|
@@ -12062,6 +13036,14 @@ function hasCredential(provider, env) {
|
|
|
12062
13036
|
const key = env.ANTHROPIC_API_KEY;
|
|
12063
13037
|
return key !== undefined && key.length > 0;
|
|
12064
13038
|
}
|
|
13039
|
+
if (provider === "openai") {
|
|
13040
|
+
const key = env.OPENAI_API_KEY;
|
|
13041
|
+
return key !== undefined && key.length > 0;
|
|
13042
|
+
}
|
|
13043
|
+
if (provider === "gemini") {
|
|
13044
|
+
const key = env.GEMINI_API_KEY ?? env.GOOGLE_API_KEY;
|
|
13045
|
+
return key !== undefined && key.length > 0;
|
|
13046
|
+
}
|
|
12065
13047
|
const compat = providerByName(provider);
|
|
12066
13048
|
if (compat) {
|
|
12067
13049
|
if (compat.requiresApiKey === false) {
|
|
@@ -12078,6 +13060,8 @@ function hasCredential(provider, env) {
|
|
|
12078
13060
|
function keyedProviderCandidates() {
|
|
12079
13061
|
return [
|
|
12080
13062
|
"anthropic",
|
|
13063
|
+
"openai",
|
|
13064
|
+
"gemini",
|
|
12081
13065
|
...OPENAI_COMPAT_PROVIDERS.filter((provider) => provider.requiresApiKey !== false).map((p) => p.name)
|
|
12082
13066
|
];
|
|
12083
13067
|
}
|
|
@@ -12153,7 +13137,9 @@ var init_single_turn = __esm(() => {
|
|
|
12153
13137
|
init_shell_config();
|
|
12154
13138
|
DEFAULT_MODELS = {
|
|
12155
13139
|
anthropic: "claude-haiku-4-5-20251001",
|
|
12156
|
-
ollama: "llama3.2"
|
|
13140
|
+
ollama: "llama3.2",
|
|
13141
|
+
openai: "gpt-5.6-luna",
|
|
13142
|
+
gemini: "gemini-2.5-flash-lite"
|
|
12157
13143
|
};
|
|
12158
13144
|
});
|
|
12159
13145
|
|
|
@@ -13196,23 +14182,23 @@ var init_slate = __esm(() => {
|
|
|
13196
14182
|
// src/flow/store.ts
|
|
13197
14183
|
var exports_store = {};
|
|
13198
14184
|
__export(exports_store, {
|
|
13199
|
-
|
|
13200
|
-
slugify: () => slugify2,
|
|
13201
|
-
resolveFlowDir: () => resolveFlowDir,
|
|
13202
|
-
readFlow: () => readFlow,
|
|
13203
|
-
readAcCriteria: () => readAcCriteria,
|
|
13204
|
-
nextFlowId: () => nextFlowId,
|
|
13205
|
-
migrateFlow: () => migrateFlow,
|
|
13206
|
-
listFlowDirs: () => listFlowDirs,
|
|
13207
|
-
groupFlowDirsById: () => groupFlowDirsById,
|
|
13208
|
-
flowsRoot: () => flowsRoot,
|
|
13209
|
-
flowIdOf: () => flowIdOf,
|
|
13210
|
-
duplicateFlowIds: () => duplicateFlowIds,
|
|
13211
|
-
deriveFlowWork: () => deriveFlowWork,
|
|
13212
|
-
assertAcIntact: () => assertAcIntact,
|
|
13213
|
-
appendJournal: () => appendJournal,
|
|
14185
|
+
acChecksum: () => acChecksum,
|
|
13214
14186
|
acPath: () => acPath,
|
|
13215
|
-
|
|
14187
|
+
appendJournal: () => appendJournal,
|
|
14188
|
+
assertAcIntact: () => assertAcIntact,
|
|
14189
|
+
deriveFlowWork: () => deriveFlowWork,
|
|
14190
|
+
duplicateFlowIds: () => duplicateFlowIds,
|
|
14191
|
+
flowIdOf: () => flowIdOf,
|
|
14192
|
+
flowsRoot: () => flowsRoot,
|
|
14193
|
+
groupFlowDirsById: () => groupFlowDirsById,
|
|
14194
|
+
listFlowDirs: () => listFlowDirs,
|
|
14195
|
+
migrateFlow: () => migrateFlow,
|
|
14196
|
+
nextFlowId: () => nextFlowId,
|
|
14197
|
+
readAcCriteria: () => readAcCriteria,
|
|
14198
|
+
readFlow: () => readFlow,
|
|
14199
|
+
resolveFlowDir: () => resolveFlowDir,
|
|
14200
|
+
slugify: () => slugify2,
|
|
14201
|
+
writeFlow: () => writeFlow
|
|
13216
14202
|
});
|
|
13217
14203
|
import { createHash as createHash7 } from "crypto";
|
|
13218
14204
|
import { appendFile as appendFile2, mkdir as mkdir26, readFile as readFile32, readdir as readdir8 } from "fs/promises";
|
|
@@ -17897,7 +18883,7 @@ function buildAgentSystemInstruction(orient, ctx = {}) {
|
|
|
17897
18883
|
Project orientation (trusted context):
|
|
17898
18884
|
${trimmed}`;
|
|
17899
18885
|
}
|
|
17900
|
-
function
|
|
18886
|
+
function parseToolInput3(raw) {
|
|
17901
18887
|
const text = raw.trim();
|
|
17902
18888
|
if (text.length === 0) {
|
|
17903
18889
|
return {};
|
|
@@ -17940,7 +18926,7 @@ function stableStringify2(value) {
|
|
|
17940
18926
|
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify2(obj[k])}`).join(",")}}`;
|
|
17941
18927
|
}
|
|
17942
18928
|
function toolCallHash(name, input2) {
|
|
17943
|
-
const parsed =
|
|
18929
|
+
const parsed = parseToolInput3(input2);
|
|
17944
18930
|
return `${name}\x00${stableStringify2(parsed)}`;
|
|
17945
18931
|
}
|
|
17946
18932
|
function budgetUsed(state) {
|
|
@@ -18371,7 +19357,7 @@ ${modelOutput}` : modelOutput,
|
|
|
18371
19357
|
}
|
|
18372
19358
|
if (options.slateSession !== undefined && options.slateSession.opened === true) {
|
|
18373
19359
|
try {
|
|
18374
|
-
const touchedPaths = extractTouchedFromToolInput(call.name,
|
|
19360
|
+
const touchedPaths = extractTouchedFromToolInput(call.name, parseToolInput3(call.input));
|
|
18375
19361
|
const touch = await recordSlateTouch(options.slateSession.dir, touchedPaths, {
|
|
18376
19362
|
runtime: { provider: deps.providerId, model: deps.modelId }
|
|
18377
19363
|
});
|
|
@@ -18630,7 +19616,7 @@ async function executeCall(call, toolByName, requestApproval, permissionMode, on
|
|
|
18630
19616
|
if (tool === undefined) {
|
|
18631
19617
|
return { output: `unknown tool: ${call.name}`, isError: true };
|
|
18632
19618
|
}
|
|
18633
|
-
const input2 =
|
|
19619
|
+
const input2 = parseToolInput3(call.input);
|
|
18634
19620
|
const validation = validateAgainstSchemaObject(tool.definition.inputSchema, input2);
|
|
18635
19621
|
if (!validation.valid) {
|
|
18636
19622
|
const detail = validation.errors.map((e) => `${e.path}: ${e.message}`).join("; ");
|
|
@@ -23336,7 +24322,7 @@ var init_github = __esm(() => {
|
|
|
23336
24322
|
});
|
|
23337
24323
|
|
|
23338
24324
|
// src/harness/tool/metaproject-adapter.ts
|
|
23339
|
-
import { readFile as readFile55 } from "fs/promises";
|
|
24325
|
+
import { readdir as readdir14, readFile as readFile55 } from "fs/promises";
|
|
23340
24326
|
import { isAbsolute, join, relative, resolve } from "path";
|
|
23341
24327
|
function errorMessage(cause) {
|
|
23342
24328
|
return cause instanceof Error ? cause.message : String(cause);
|
|
@@ -23357,6 +24343,131 @@ function confineToWiki(cwd, candidate) {
|
|
|
23357
24343
|
}
|
|
23358
24344
|
return target;
|
|
23359
24345
|
}
|
|
24346
|
+
function confineToSkills(cwd, candidate) {
|
|
24347
|
+
const skillsRoot = join(cwd, ".metaproject", "skills", "gdskills");
|
|
24348
|
+
const target = resolve(cwd, candidate);
|
|
24349
|
+
const rel = relative(skillsRoot, target);
|
|
24350
|
+
if (rel === "") {
|
|
24351
|
+
return null;
|
|
24352
|
+
}
|
|
24353
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
24354
|
+
return null;
|
|
24355
|
+
}
|
|
24356
|
+
return target;
|
|
24357
|
+
}
|
|
24358
|
+
function stripSkillFieldQuotes(value) {
|
|
24359
|
+
if (value.length >= 2) {
|
|
24360
|
+
const first = value[0];
|
|
24361
|
+
const last = value[value.length - 1];
|
|
24362
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
24363
|
+
return value.slice(1, -1);
|
|
24364
|
+
}
|
|
24365
|
+
}
|
|
24366
|
+
return value;
|
|
24367
|
+
}
|
|
24368
|
+
function parseSkillFrontmatter(content) {
|
|
24369
|
+
if (!content.startsWith("---")) {
|
|
24370
|
+
return {};
|
|
24371
|
+
}
|
|
24372
|
+
const end = content.indexOf(`
|
|
24373
|
+
---`, 3);
|
|
24374
|
+
if (end === -1) {
|
|
24375
|
+
return {};
|
|
24376
|
+
}
|
|
24377
|
+
const lines = content.slice(3, end).split(`
|
|
24378
|
+
`);
|
|
24379
|
+
let description;
|
|
24380
|
+
const triggers = [];
|
|
24381
|
+
let inTriggers = false;
|
|
24382
|
+
for (const line of lines) {
|
|
24383
|
+
const descMatch = /^description:\s*(.*)$/.exec(line);
|
|
24384
|
+
if (descMatch !== null && descMatch[1] !== undefined) {
|
|
24385
|
+
description = stripSkillFieldQuotes(descMatch[1].trim());
|
|
24386
|
+
inTriggers = false;
|
|
24387
|
+
continue;
|
|
24388
|
+
}
|
|
24389
|
+
if (/^triggers:\s*$/.test(line)) {
|
|
24390
|
+
inTriggers = true;
|
|
24391
|
+
continue;
|
|
24392
|
+
}
|
|
24393
|
+
if (inTriggers) {
|
|
24394
|
+
const itemMatch = /^\s+-\s*(.+)$/.exec(line);
|
|
24395
|
+
if (itemMatch !== null && itemMatch[1] !== undefined) {
|
|
24396
|
+
triggers.push(stripSkillFieldQuotes(itemMatch[1].trim()));
|
|
24397
|
+
continue;
|
|
24398
|
+
}
|
|
24399
|
+
inTriggers = false;
|
|
24400
|
+
}
|
|
24401
|
+
}
|
|
24402
|
+
return { ...description !== undefined ? { description } : {}, ...triggers.length > 0 ? { triggers } : {} };
|
|
24403
|
+
}
|
|
24404
|
+
async function parseCatalogSummaries(cwd) {
|
|
24405
|
+
const summaries = new Map;
|
|
24406
|
+
let content;
|
|
24407
|
+
try {
|
|
24408
|
+
content = await readFile55(join(cwd, ".metaproject", "skills", "catalog.md"), "utf8");
|
|
24409
|
+
} catch {
|
|
24410
|
+
return summaries;
|
|
24411
|
+
}
|
|
24412
|
+
const rowPattern = /^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*$/;
|
|
24413
|
+
for (const line of content.split(`
|
|
24414
|
+
`)) {
|
|
24415
|
+
const match = rowPattern.exec(line);
|
|
24416
|
+
if (match === null) {
|
|
24417
|
+
continue;
|
|
24418
|
+
}
|
|
24419
|
+
const [, name, , purpose] = match;
|
|
24420
|
+
if (name === undefined || purpose === undefined || name === "Skill" || /^-+$/.test(name)) {
|
|
24421
|
+
continue;
|
|
24422
|
+
}
|
|
24423
|
+
summaries.set(name, purpose);
|
|
24424
|
+
}
|
|
24425
|
+
return summaries;
|
|
24426
|
+
}
|
|
24427
|
+
async function walkSkillCatalog(cwd) {
|
|
24428
|
+
const root = join(cwd, ".metaproject", "skills", "gdskills");
|
|
24429
|
+
const entries = [];
|
|
24430
|
+
let categoryDirs;
|
|
24431
|
+
try {
|
|
24432
|
+
categoryDirs = await readdir14(root, { withFileTypes: true });
|
|
24433
|
+
} catch {
|
|
24434
|
+
return [];
|
|
24435
|
+
}
|
|
24436
|
+
const catalogSummaries = await parseCatalogSummaries(cwd);
|
|
24437
|
+
for (const categoryDir of categoryDirs) {
|
|
24438
|
+
if (!categoryDir.isDirectory()) {
|
|
24439
|
+
continue;
|
|
24440
|
+
}
|
|
24441
|
+
const categoryPath = join(root, categoryDir.name);
|
|
24442
|
+
let skillDirs;
|
|
24443
|
+
try {
|
|
24444
|
+
skillDirs = await readdir14(categoryPath, { withFileTypes: true });
|
|
24445
|
+
} catch {
|
|
24446
|
+
continue;
|
|
24447
|
+
}
|
|
24448
|
+
for (const skillDir of skillDirs) {
|
|
24449
|
+
if (!skillDir.isDirectory()) {
|
|
24450
|
+
continue;
|
|
24451
|
+
}
|
|
24452
|
+
const skillMdPath = join(categoryPath, skillDir.name, "SKILL.md");
|
|
24453
|
+
let content;
|
|
24454
|
+
try {
|
|
24455
|
+
content = await readFile55(skillMdPath, "utf8");
|
|
24456
|
+
} catch {
|
|
24457
|
+
continue;
|
|
24458
|
+
}
|
|
24459
|
+
const { description, triggers } = parseSkillFrontmatter(content);
|
|
24460
|
+
entries.push({
|
|
24461
|
+
name: skillDir.name,
|
|
24462
|
+
path: relative(cwd, skillMdPath),
|
|
24463
|
+
category: categoryDir.name,
|
|
24464
|
+
description: description ?? catalogSummaries.get(skillDir.name) ?? "",
|
|
24465
|
+
...triggers !== undefined ? { triggers } : {}
|
|
24466
|
+
});
|
|
24467
|
+
}
|
|
24468
|
+
}
|
|
24469
|
+
return entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
24470
|
+
}
|
|
23360
24471
|
function createMetaprojectAdapter(cwd, overrides = {}) {
|
|
23361
24472
|
const deps = { ...DEFAULT_DEPS, ...overrides };
|
|
23362
24473
|
const gdgraph = deps.createGdgraphService();
|
|
@@ -23624,6 +24735,36 @@ function createMetaprojectAdapter(cwd, overrides = {}) {
|
|
|
23624
24735
|
} catch (cause) {
|
|
23625
24736
|
return { file: input2.file, backlinks: [], error: errorMessage(cause) };
|
|
23626
24737
|
}
|
|
24738
|
+
},
|
|
24739
|
+
async skillsCatalog() {
|
|
24740
|
+
const skills = await walkSkillCatalog(cwd);
|
|
24741
|
+
return { skills, generatedAt: deps.now() };
|
|
24742
|
+
},
|
|
24743
|
+
async loadSkill(input2) {
|
|
24744
|
+
const catalog = await walkSkillCatalog(cwd);
|
|
24745
|
+
const byName = catalog.find((entry) => entry.name === input2.name);
|
|
24746
|
+
if (byName !== undefined) {
|
|
24747
|
+
try {
|
|
24748
|
+
const content = await readFile55(join(cwd, byName.path), "utf8");
|
|
24749
|
+
return { name: input2.name, path: byName.path, content, found: true };
|
|
24750
|
+
} catch {
|
|
24751
|
+
return { name: input2.name, path: "", content: "", found: false };
|
|
24752
|
+
}
|
|
24753
|
+
}
|
|
24754
|
+
const confined = confineToSkills(cwd, input2.name);
|
|
24755
|
+
if (confined === null) {
|
|
24756
|
+
return { name: input2.name, path: "", content: "", found: false };
|
|
24757
|
+
}
|
|
24758
|
+
const byPath = catalog.find((entry) => join(cwd, entry.path) === confined);
|
|
24759
|
+
if (byPath === undefined) {
|
|
24760
|
+
return { name: input2.name, path: "", content: "", found: false };
|
|
24761
|
+
}
|
|
24762
|
+
try {
|
|
24763
|
+
const content = await readFile55(confined, "utf8");
|
|
24764
|
+
return { name: input2.name, path: byPath.path, content, found: true };
|
|
24765
|
+
} catch {
|
|
24766
|
+
return { name: input2.name, path: "", content: "", found: false };
|
|
24767
|
+
}
|
|
23627
24768
|
}
|
|
23628
24769
|
};
|
|
23629
24770
|
}
|
|
@@ -23660,6 +24801,7 @@ var init_metaproject_adapter = __esm(() => {
|
|
|
23660
24801
|
}),
|
|
23661
24802
|
wikiAsk,
|
|
23662
24803
|
wikiPagesForFile,
|
|
24804
|
+
now: () => new Date().toISOString(),
|
|
23663
24805
|
repomapCompute: async (cwd, options) => {
|
|
23664
24806
|
const [graph, config] = await Promise.all([loadGraph(cwd), loadGdgraphConfig(cwd)]);
|
|
23665
24807
|
return computeRepomap(graph, config, options);
|
|
@@ -23734,6 +24876,24 @@ function formatWiki(result) {
|
|
|
23734
24876
|
}
|
|
23735
24877
|
return { output: result.content.length > 0 ? result.content : "(empty page)", isError: false };
|
|
23736
24878
|
}
|
|
24879
|
+
function formatSkillsCatalog(result) {
|
|
24880
|
+
if (result.skills.length === 0) {
|
|
24881
|
+
return { output: "No skills found under .metaproject/skills/gdskills/.", isError: false };
|
|
24882
|
+
}
|
|
24883
|
+
const lines = result.skills.map((skill2) => {
|
|
24884
|
+
const triggers = skill2.triggers !== undefined && skill2.triggers.length > 0 ? ` [triggers: ${skill2.triggers.join(", ")}]` : "";
|
|
24885
|
+
return ` - ${skill2.name} (${skill2.category}) \u2014 ${skill2.description || "(no description)"}${triggers}
|
|
24886
|
+
${skill2.path}`;
|
|
24887
|
+
});
|
|
24888
|
+
return { output: [`Skills (${result.skills.length}):`, ...lines].join(`
|
|
24889
|
+
`), isError: false };
|
|
24890
|
+
}
|
|
24891
|
+
function formatSkillLoad(result) {
|
|
24892
|
+
if (!result.found) {
|
|
24893
|
+
return { output: `skill_load: no skill found for '${result.name}'.`, isError: true };
|
|
24894
|
+
}
|
|
24895
|
+
return { output: result.content, isError: false };
|
|
24896
|
+
}
|
|
23737
24897
|
function formatPath(result) {
|
|
23738
24898
|
if (result.error !== undefined) {
|
|
23739
24899
|
return { output: `graph_path failed: ${result.error}`, isError: true };
|
|
@@ -23847,7 +25007,7 @@ function toInteractiveTools(ops, port) {
|
|
|
23847
25007
|
invoke: (input2) => op.invoke(port, input2)
|
|
23848
25008
|
}));
|
|
23849
25009
|
}
|
|
23850
|
-
var AFFECTED_OUTPUT_SCHEMA, QUERY_OUTPUT_SCHEMA, MEMORY_OUTPUT_SCHEMA, WIKI_OUTPUT_SCHEMA, SEARCH_OUTPUT_SCHEMA, PATH_OUTPUT_SCHEMA, TEST_RELATED_OUTPUT_SCHEMA, HEALTH_OUTPUT_SCHEMA, SYMBOL_OUTPUT_SCHEMA, REPOMAP_OUTPUT_SCHEMA, WIKI_ASK_OUTPUT_SCHEMA, WIKI_BACKLINKS_OUTPUT_SCHEMA, FLOW_STATUS_OUTPUT_SCHEMA, METAPROJECT_OPERATIONS;
|
|
25010
|
+
var AFFECTED_OUTPUT_SCHEMA, QUERY_OUTPUT_SCHEMA, MEMORY_OUTPUT_SCHEMA, WIKI_OUTPUT_SCHEMA, SEARCH_OUTPUT_SCHEMA, PATH_OUTPUT_SCHEMA, TEST_RELATED_OUTPUT_SCHEMA, HEALTH_OUTPUT_SCHEMA, SYMBOL_OUTPUT_SCHEMA, REPOMAP_OUTPUT_SCHEMA, WIKI_ASK_OUTPUT_SCHEMA, WIKI_BACKLINKS_OUTPUT_SCHEMA, FLOW_STATUS_OUTPUT_SCHEMA, SKILLS_CATALOG_OUTPUT_SCHEMA, SKILL_LOAD_OUTPUT_SCHEMA, METAPROJECT_OPERATIONS;
|
|
23851
25011
|
var init_metaproject_operations = __esm(() => {
|
|
23852
25012
|
AFFECTED_OUTPUT_SCHEMA = {
|
|
23853
25013
|
type: "object",
|
|
@@ -23984,6 +25144,24 @@ var init_metaproject_operations = __esm(() => {
|
|
|
23984
25144
|
},
|
|
23985
25145
|
required: ["flows"]
|
|
23986
25146
|
};
|
|
25147
|
+
SKILLS_CATALOG_OUTPUT_SCHEMA = {
|
|
25148
|
+
type: "object",
|
|
25149
|
+
properties: {
|
|
25150
|
+
skills: { type: "array" },
|
|
25151
|
+
generatedAt: { type: "string" }
|
|
25152
|
+
},
|
|
25153
|
+
required: ["skills", "generatedAt"]
|
|
25154
|
+
};
|
|
25155
|
+
SKILL_LOAD_OUTPUT_SCHEMA = {
|
|
25156
|
+
type: "object",
|
|
25157
|
+
properties: {
|
|
25158
|
+
name: { type: "string" },
|
|
25159
|
+
path: { type: "string" },
|
|
25160
|
+
content: { type: "string" },
|
|
25161
|
+
found: { type: "boolean" }
|
|
25162
|
+
},
|
|
25163
|
+
required: ["name", "path", "content", "found"]
|
|
25164
|
+
};
|
|
23987
25165
|
METAPROJECT_OPERATIONS = [
|
|
23988
25166
|
{
|
|
23989
25167
|
name: "search_code",
|
|
@@ -24260,6 +25438,47 @@ var init_metaproject_operations = __esm(() => {
|
|
|
24260
25438
|
const id = typeof input2.id === "string" && input2.id.trim().length > 0 ? input2.id.trim() : undefined;
|
|
24261
25439
|
return formatFlowStatus(await port.flowStatus(id !== undefined ? { id } : {}));
|
|
24262
25440
|
}
|
|
25441
|
+
},
|
|
25442
|
+
{
|
|
25443
|
+
name: "skills_catalog",
|
|
25444
|
+
risk: "read",
|
|
25445
|
+
module: "gdskills",
|
|
25446
|
+
description: "List every skill discovered under .metaproject/skills/gdskills/ \u2014 name, category, description, and " + "triggers for each. Use this instead of reading .metaproject/index.md or catalog.md to find which skill " + "applies to a task. No input.",
|
|
25447
|
+
inputSchema: {
|
|
25448
|
+
type: "object",
|
|
25449
|
+
properties: {},
|
|
25450
|
+
additionalProperties: false
|
|
25451
|
+
},
|
|
25452
|
+
outputSchema: SKILLS_CATALOG_OUTPUT_SCHEMA,
|
|
25453
|
+
invoke: async (port) => {
|
|
25454
|
+
if (port.skillsCatalog === undefined) {
|
|
25455
|
+
return { output: "skills_catalog is not available in this session.", isError: true };
|
|
25456
|
+
}
|
|
25457
|
+
return formatSkillsCatalog(await port.skillsCatalog({}));
|
|
25458
|
+
}
|
|
25459
|
+
},
|
|
25460
|
+
{
|
|
25461
|
+
name: "skill_load",
|
|
25462
|
+
risk: "read",
|
|
25463
|
+
module: "gdskills",
|
|
25464
|
+
description: `Load one skill's full SKILL.md content by name (e.g. "flow-orchestrator") or exact project-relative ` + "path, as returned by `skills_catalog`. Input: { name: string }.",
|
|
25465
|
+
inputSchema: {
|
|
25466
|
+
type: "object",
|
|
25467
|
+
properties: { name: { type: "string" } },
|
|
25468
|
+
required: ["name"],
|
|
25469
|
+
additionalProperties: false
|
|
25470
|
+
},
|
|
25471
|
+
outputSchema: SKILL_LOAD_OUTPUT_SCHEMA,
|
|
25472
|
+
invoke: async (port, input2) => {
|
|
25473
|
+
if (port.loadSkill === undefined) {
|
|
25474
|
+
return { output: "skill_load is not available in this session.", isError: true };
|
|
25475
|
+
}
|
|
25476
|
+
const name = requireString(input2, "name", "skill_load");
|
|
25477
|
+
if ("error" in name) {
|
|
25478
|
+
return name.error;
|
|
25479
|
+
}
|
|
25480
|
+
return formatSkillLoad(await port.loadSkill({ name: name.value }));
|
|
25481
|
+
}
|
|
24263
25482
|
}
|
|
24264
25483
|
];
|
|
24265
25484
|
});
|
|
@@ -24513,30 +25732,30 @@ var init_staleness2 = __esm(() => {
|
|
|
24513
25732
|
// src/wiki/enrich.ts
|
|
24514
25733
|
var exports_enrich2 = {};
|
|
24515
25734
|
__export(exports_enrich2, {
|
|
24516
|
-
|
|
24517
|
-
validateEnrichedMarkdown: () => validateEnrichedMarkdown,
|
|
24518
|
-
setFrontmatterStatus: () => setFrontmatterStatus,
|
|
24519
|
-
selectPages: () => selectPages,
|
|
24520
|
-
saveResumeState: () => saveResumeState,
|
|
24521
|
-
resumeStatePath: () => resumeStatePath,
|
|
24522
|
-
resolveEnrichProviderModel: () => resolveEnrichProviderModel,
|
|
24523
|
-
repairEnrichedFrontmatter: () => repairEnrichedFrontmatter,
|
|
24524
|
-
planWikiEnrich: () => planWikiEnrich,
|
|
24525
|
-
parseBatchResponse: () => parseBatchResponse,
|
|
24526
|
-
mapPool: () => mapPool,
|
|
24527
|
-
loadResumeState: () => loadResumeState,
|
|
24528
|
-
isWikiEnrichIntent: () => isWikiEnrichIntent,
|
|
24529
|
-
hasYamlFrontmatter: () => hasYamlFrontmatter,
|
|
24530
|
-
hasCredential: () => hasCredential,
|
|
24531
|
-
groupLightPagesIntoBatches: () => groupLightPagesIntoBatches,
|
|
24532
|
-
extractYamlFrontmatterBlock: () => extractYamlFrontmatterBlock,
|
|
24533
|
-
ensureWikiFrontmatter: () => ensureWikiFrontmatter,
|
|
24534
|
-
defaultEnrichProgress: () => defaultEnrichProgress,
|
|
24535
|
-
buildBatchUserPrompt: () => buildBatchUserPrompt,
|
|
24536
|
-
batchGroupKey: () => batchGroupKey,
|
|
24537
|
-
MAX_CONCURRENCY: () => MAX_CONCURRENCY,
|
|
25735
|
+
DEFAULT_CONCURRENCY: () => DEFAULT_CONCURRENCY,
|
|
24538
25736
|
DEFAULT_MAX_OUTPUT_TOKENS: () => DEFAULT_MAX_OUTPUT_TOKENS,
|
|
24539
|
-
|
|
25737
|
+
MAX_CONCURRENCY: () => MAX_CONCURRENCY,
|
|
25738
|
+
batchGroupKey: () => batchGroupKey,
|
|
25739
|
+
buildBatchUserPrompt: () => buildBatchUserPrompt,
|
|
25740
|
+
defaultEnrichProgress: () => defaultEnrichProgress,
|
|
25741
|
+
ensureWikiFrontmatter: () => ensureWikiFrontmatter,
|
|
25742
|
+
extractYamlFrontmatterBlock: () => extractYamlFrontmatterBlock,
|
|
25743
|
+
groupLightPagesIntoBatches: () => groupLightPagesIntoBatches,
|
|
25744
|
+
hasCredential: () => hasCredential,
|
|
25745
|
+
hasYamlFrontmatter: () => hasYamlFrontmatter,
|
|
25746
|
+
isWikiEnrichIntent: () => isWikiEnrichIntent,
|
|
25747
|
+
loadResumeState: () => loadResumeState,
|
|
25748
|
+
mapPool: () => mapPool,
|
|
25749
|
+
parseBatchResponse: () => parseBatchResponse,
|
|
25750
|
+
planWikiEnrich: () => planWikiEnrich,
|
|
25751
|
+
repairEnrichedFrontmatter: () => repairEnrichedFrontmatter,
|
|
25752
|
+
resolveEnrichProviderModel: () => resolveEnrichProviderModel,
|
|
25753
|
+
resumeStatePath: () => resumeStatePath,
|
|
25754
|
+
saveResumeState: () => saveResumeState,
|
|
25755
|
+
selectPages: () => selectPages,
|
|
25756
|
+
setFrontmatterStatus: () => setFrontmatterStatus,
|
|
25757
|
+
validateEnrichedMarkdown: () => validateEnrichedMarkdown,
|
|
25758
|
+
wikiEnrich: () => wikiEnrich
|
|
24540
25759
|
});
|
|
24541
25760
|
import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
24542
25761
|
import { readFile as readFile57, writeFile as writeFile36 } from "fs/promises";
|
|
@@ -25588,9 +26807,9 @@ var init_enrich2 = __esm(() => {
|
|
|
25588
26807
|
// src/sync/hooks.ts
|
|
25589
26808
|
var exports_hooks = {};
|
|
25590
26809
|
__export(exports_hooks, {
|
|
25591
|
-
|
|
26810
|
+
SYNC_HOOKS: () => SYNC_HOOKS,
|
|
25592
26811
|
installSyncHooks: () => installSyncHooks,
|
|
25593
|
-
|
|
26812
|
+
uninstallSyncHooks: () => uninstallSyncHooks
|
|
25594
26813
|
});
|
|
25595
26814
|
import { chmod as chmod3, mkdir as mkdir42, readFile as readFile59, writeFile as writeFile38 } from "fs/promises";
|
|
25596
26815
|
import path111 from "path";
|
|
@@ -25773,8 +26992,8 @@ var init_reflect = __esm(() => {
|
|
|
25773
26992
|
// src/lib/narrate.ts
|
|
25774
26993
|
var exports_narrate = {};
|
|
25775
26994
|
__export(exports_narrate, {
|
|
25776
|
-
|
|
25777
|
-
|
|
26995
|
+
formatMissingCredentialHint: () => formatMissingCredentialHint,
|
|
26996
|
+
narrate: () => narrate
|
|
25778
26997
|
});
|
|
25779
26998
|
function formatMissingCredentialHint(provider) {
|
|
25780
26999
|
const env = envWithSavedApiKeys(process.env);
|
|
@@ -26206,9 +27425,9 @@ var init_memory = __esm(() => {
|
|
|
26206
27425
|
// src/lib/contained-path.ts
|
|
26207
27426
|
var exports_contained_path = {};
|
|
26208
27427
|
__export(exports_contained_path, {
|
|
26209
|
-
|
|
27428
|
+
resolveContainedPath: () => resolveContainedPath,
|
|
26210
27429
|
resolveContainedPathSync: () => resolveContainedPathSync,
|
|
26211
|
-
|
|
27430
|
+
resolveProjectRoot: () => resolveProjectRoot2
|
|
26212
27431
|
});
|
|
26213
27432
|
import { realpath as realpath3 } from "fs/promises";
|
|
26214
27433
|
import { existsSync as existsSync21, realpathSync as realpathSync2 } from "fs";
|
|
@@ -32398,10 +33617,72 @@ var GENERIC_RUNTIME = {
|
|
|
32398
33617
|
validate: mcpValidate("generic"),
|
|
32399
33618
|
hasManaged: mcpHasManaged
|
|
32400
33619
|
};
|
|
33620
|
+
function readVscodeServers(settings) {
|
|
33621
|
+
return typeof settings.servers === "object" && settings.servers !== null && !Array.isArray(settings.servers) ? { ...settings.servers } : {};
|
|
33622
|
+
}
|
|
33623
|
+
function vscodeManagedEntry(projectRoot) {
|
|
33624
|
+
return {
|
|
33625
|
+
type: "stdio",
|
|
33626
|
+
...mcpServerEntry(projectRoot),
|
|
33627
|
+
[MCP_MANAGED_KEY]: MCP_MANAGED_SENTINEL
|
|
33628
|
+
};
|
|
33629
|
+
}
|
|
33630
|
+
function vscodeMerge(settings, projectRoot) {
|
|
33631
|
+
const servers = readVscodeServers(settings);
|
|
33632
|
+
servers[MCP_SERVER_NAME] = vscodeManagedEntry(projectRoot);
|
|
33633
|
+
settings.servers = servers;
|
|
33634
|
+
return settings;
|
|
33635
|
+
}
|
|
33636
|
+
function vscodeStrip(settings) {
|
|
33637
|
+
if (typeof settings.servers !== "object" || settings.servers === null || Array.isArray(settings.servers)) {
|
|
33638
|
+
return settings;
|
|
33639
|
+
}
|
|
33640
|
+
const servers = { ...settings.servers };
|
|
33641
|
+
if (isManagedEntry(servers[MCP_SERVER_NAME])) {
|
|
33642
|
+
delete servers[MCP_SERVER_NAME];
|
|
33643
|
+
}
|
|
33644
|
+
if (Object.keys(servers).length > 0)
|
|
33645
|
+
settings.servers = servers;
|
|
33646
|
+
else
|
|
33647
|
+
delete settings.servers;
|
|
33648
|
+
return settings;
|
|
33649
|
+
}
|
|
33650
|
+
function vscodeValidate(settings) {
|
|
33651
|
+
const errors = [];
|
|
33652
|
+
const servers = settings.servers;
|
|
33653
|
+
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
33654
|
+
errors.push("vscode: servers is missing or not an object");
|
|
33655
|
+
return errors;
|
|
33656
|
+
}
|
|
33657
|
+
const entry = servers[MCP_SERVER_NAME];
|
|
33658
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
33659
|
+
errors.push(`vscode: missing servers.${MCP_SERVER_NAME} entry`);
|
|
33660
|
+
return errors;
|
|
33661
|
+
}
|
|
33662
|
+
if (entry.type !== "stdio") {
|
|
33663
|
+
errors.push(`vscode: servers.${MCP_SERVER_NAME}.type must be "stdio"`);
|
|
33664
|
+
}
|
|
33665
|
+
if (entry.command !== MCP_SERVER_COMMAND) {
|
|
33666
|
+
errors.push(`vscode: servers.${MCP_SERVER_NAME}.command must be "${MCP_SERVER_COMMAND}"`);
|
|
33667
|
+
}
|
|
33668
|
+
return errors;
|
|
33669
|
+
}
|
|
33670
|
+
function vscodeHasManaged(settings) {
|
|
33671
|
+
return isManagedEntry(readVscodeServers(settings)[MCP_SERVER_NAME]);
|
|
33672
|
+
}
|
|
33673
|
+
var VSCODE_RUNTIME = {
|
|
33674
|
+
id: "vscode",
|
|
33675
|
+
settingsPath: (root) => path40.join(root, ".vscode", "mcp.json"),
|
|
33676
|
+
merge: vscodeMerge,
|
|
33677
|
+
strip: vscodeStrip,
|
|
33678
|
+
validate: vscodeValidate,
|
|
33679
|
+
hasManaged: vscodeHasManaged
|
|
33680
|
+
};
|
|
32401
33681
|
var MCP_CLIENT_RUNTIMES = [
|
|
32402
33682
|
CURSOR_RUNTIME,
|
|
32403
33683
|
CLAUDE_RUNTIME2,
|
|
32404
33684
|
OPENCODE_RUNTIME,
|
|
33685
|
+
VSCODE_RUNTIME,
|
|
32405
33686
|
GENERIC_RUNTIME
|
|
32406
33687
|
];
|
|
32407
33688
|
var ALL_RUNTIME_IDS = ["cursor", "claude", "opencode"];
|
|
@@ -32499,16 +33780,18 @@ protocol adapter \u2014 it defines no new module logic.
|
|
|
32499
33780
|
requires \`http.enabled=true\` in this module's manifest entry).
|
|
32500
33781
|
- \`keryx mcp serve --cwd <project-root>\` \u2014 expose a specific project,
|
|
32501
33782
|
independent of the MCP client's launch directory.
|
|
32502
|
-
- \`keryx mcp install --runtime <cursor|claude|opencode|generic|all> [--dry-run]\` \u2014
|
|
33783
|
+
- \`keryx mcp install --runtime <cursor|claude|opencode|vscode|generic|all> [--dry-run]\` \u2014
|
|
32503
33784
|
wire this project into an editor/agent: writes a project-local client
|
|
32504
33785
|
config (cursor \u2192 \`.cursor/mcp.json\`, claude \u2192 \`.mcp.json\`, opencode \u2192
|
|
32505
|
-
\`opencode.json\`) and sets
|
|
32506
|
-
prints the change without
|
|
32507
|
-
|
|
32508
|
-
|
|
32509
|
-
|
|
32510
|
-
cursor + claude +
|
|
32511
|
-
|
|
33786
|
+
\`opencode.json\`, vscode \u2192 \`.vscode/mcp.json\`) and sets
|
|
33787
|
+
\`modules.mcp.enabled=true\`. \`--dry-run\` prints the change without
|
|
33788
|
+
writing anything. This is the command to run when a user asks to
|
|
33789
|
+
"connect" or "enable" MCP for this project \u2014 it is the full, real setup
|
|
33790
|
+
step; hand-editing a client config file directly is unnecessary and skips
|
|
33791
|
+
setting \`modules.mcp.enabled\`. \`all\` expands to cursor + claude +
|
|
33792
|
+
opencode; \`vscode\` is opt-in only (not bundled into \`all\`) \u2014 request it
|
|
33793
|
+
explicitly with \`--runtime vscode\`.
|
|
33794
|
+
- \`keryx mcp uninstall --runtime <cursor|claude|opencode|vscode|generic|all>\` \u2014
|
|
32512
33795
|
remove the managed client config again.
|
|
32513
33796
|
- **codex CLI**: not a \`--runtime\` here \u2014 codex's client config is a single
|
|
32514
33797
|
GLOBAL \`~/.codex/config.toml\`, not a project-local file, and it already
|
|
@@ -32790,7 +34073,14 @@ skill's Reporting section).
|
|
|
32790
34073
|
}
|
|
32791
34074
|
|
|
32792
34075
|
// src/commands/init.ts
|
|
32793
|
-
var MCP_INIT_RUNTIMES = [
|
|
34076
|
+
var MCP_INIT_RUNTIMES = [
|
|
34077
|
+
"cursor",
|
|
34078
|
+
"claude",
|
|
34079
|
+
"opencode",
|
|
34080
|
+
"vscode",
|
|
34081
|
+
"generic",
|
|
34082
|
+
"skip"
|
|
34083
|
+
];
|
|
32794
34084
|
async function initCommand(args) {
|
|
32795
34085
|
const options = parseInitArgs(args);
|
|
32796
34086
|
if (options.help) {
|
|
@@ -35962,7 +37252,7 @@ the derived layers in step.
|
|
|
35962
37252
|
init_args();
|
|
35963
37253
|
init_fs();
|
|
35964
37254
|
init_json();
|
|
35965
|
-
import { readdir as
|
|
37255
|
+
import { readdir as readdir18, readFile as readFile64 } from "fs/promises";
|
|
35966
37256
|
import path120 from "path";
|
|
35967
37257
|
|
|
35968
37258
|
// src/gdskills/contracts.ts
|
|
@@ -36094,7 +37384,7 @@ async function validateValue(value, schema, valuePath, errors, rootSchema, schem
|
|
|
36094
37384
|
});
|
|
36095
37385
|
}
|
|
36096
37386
|
}
|
|
36097
|
-
if (
|
|
37387
|
+
if (isPlainObject8(value)) {
|
|
36098
37388
|
const required2 = schema.required ?? [];
|
|
36099
37389
|
for (const key of required2) {
|
|
36100
37390
|
if (!(key in value)) {
|
|
@@ -36114,7 +37404,7 @@ async function validateValue(value, schema, valuePath, errors, rootSchema, schem
|
|
|
36114
37404
|
path: `${valuePath}.${key}`,
|
|
36115
37405
|
message: "Additional property is not allowed"
|
|
36116
37406
|
});
|
|
36117
|
-
} else if (
|
|
37407
|
+
} else if (isPlainObject8(schema.additionalProperties)) {
|
|
36118
37408
|
await validateValue(nestedValue, schema.additionalProperties, `${valuePath}.${key}`, errors, rootSchema, schemaCache);
|
|
36119
37409
|
}
|
|
36120
37410
|
}
|
|
@@ -36173,11 +37463,11 @@ function matchesType3(value, type) {
|
|
|
36173
37463
|
if (entry === "integer")
|
|
36174
37464
|
return Number.isInteger(value);
|
|
36175
37465
|
if (entry === "object")
|
|
36176
|
-
return
|
|
37466
|
+
return isPlainObject8(value);
|
|
36177
37467
|
return typeof value === entry;
|
|
36178
37468
|
});
|
|
36179
37469
|
}
|
|
36180
|
-
function
|
|
37470
|
+
function isPlainObject8(value) {
|
|
36181
37471
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36182
37472
|
}
|
|
36183
37473
|
function formatType(type) {
|
|
@@ -36594,7 +37884,7 @@ function unique(values) {
|
|
|
36594
37884
|
// src/gdskills/export.ts
|
|
36595
37885
|
init_fs();
|
|
36596
37886
|
init_json();
|
|
36597
|
-
import { copyFile as copyFile3, mkdir as mkdir45, readdir as
|
|
37887
|
+
import { copyFile as copyFile3, mkdir as mkdir45, readdir as readdir16, writeFile as writeFile40 } from "fs/promises";
|
|
36598
37888
|
import path117 from "path";
|
|
36599
37889
|
|
|
36600
37890
|
// src/gdskills/resolve.ts
|
|
@@ -36644,7 +37934,7 @@ async function normalizePackagePath(candidate) {
|
|
|
36644
37934
|
// src/gdskills/export-plugin.ts
|
|
36645
37935
|
init_fs();
|
|
36646
37936
|
init_json();
|
|
36647
|
-
import { copyFile as copyFile2, mkdir as mkdir44, readdir as
|
|
37937
|
+
import { copyFile as copyFile2, mkdir as mkdir44, readdir as readdir15, readFile as readFile62, writeFile as writeFile39 } from "fs/promises";
|
|
36648
37938
|
import path116 from "path";
|
|
36649
37939
|
var SAFE_DIRS = ["references", "templates", "assets", "scripts"];
|
|
36650
37940
|
function skillTitle(skillMd, fallback) {
|
|
@@ -36666,7 +37956,7 @@ function skillVersion(skillMd) {
|
|
|
36666
37956
|
return skillMd.match(/^Version:\s*(.+)$/m)?.[1]?.trim() ?? "0.1.0";
|
|
36667
37957
|
}
|
|
36668
37958
|
async function listFiles(root) {
|
|
36669
|
-
const entries = await
|
|
37959
|
+
const entries = await readdir15(root, { withFileTypes: true });
|
|
36670
37960
|
const files = [];
|
|
36671
37961
|
for (const entry of entries) {
|
|
36672
37962
|
const full = path116.join(root, entry.name);
|
|
@@ -36856,7 +38146,7 @@ async function copyDirectoryIfExists(sourceDir, targetDir) {
|
|
|
36856
38146
|
}
|
|
36857
38147
|
}
|
|
36858
38148
|
async function listFiles2(root) {
|
|
36859
|
-
const entries = await
|
|
38149
|
+
const entries = await readdir16(root, { withFileTypes: true });
|
|
36860
38150
|
const files = [];
|
|
36861
38151
|
for (const entry of entries) {
|
|
36862
38152
|
const entryPath = path117.join(root, entry.name);
|
|
@@ -36877,7 +38167,7 @@ function inferModuleFromPackageRoot(packageRoot) {
|
|
|
36877
38167
|
|
|
36878
38168
|
// src/gdskills/sync.ts
|
|
36879
38169
|
init_fs();
|
|
36880
|
-
import { copyFile as copyFile4, mkdir as mkdir46, readdir as
|
|
38170
|
+
import { copyFile as copyFile4, mkdir as mkdir46, readdir as readdir17, writeFile as writeFile41 } from "fs/promises";
|
|
36881
38171
|
import path118 from "path";
|
|
36882
38172
|
async function syncRuntimeSkills(projectRoot, options) {
|
|
36883
38173
|
const metaprojectRoot = path118.join(projectRoot, ".metaproject");
|
|
@@ -36942,7 +38232,7 @@ function validateSyncTarget(projectRoot, targetRoot) {
|
|
|
36942
38232
|
}
|
|
36943
38233
|
}
|
|
36944
38234
|
async function listSkillArtifactDirs(sourceRoot) {
|
|
36945
|
-
const entries = await
|
|
38235
|
+
const entries = await readdir17(sourceRoot, { withFileTypes: true });
|
|
36946
38236
|
const dirs = [];
|
|
36947
38237
|
for (const entry of entries) {
|
|
36948
38238
|
if (!entry.isDirectory()) {
|
|
@@ -36972,7 +38262,7 @@ async function copyDirectory(sourceDir, targetDir) {
|
|
|
36972
38262
|
}
|
|
36973
38263
|
}
|
|
36974
38264
|
async function listFiles3(root) {
|
|
36975
|
-
const entries = await
|
|
38265
|
+
const entries = await readdir17(root, { withFileTypes: true });
|
|
36976
38266
|
const files = [];
|
|
36977
38267
|
for (const entry of entries) {
|
|
36978
38268
|
const entryPath = path118.join(root, entry.name);
|
|
@@ -38150,7 +39440,7 @@ async function listJsonFiles(root) {
|
|
|
38150
39440
|
if (!await pathExists(root)) {
|
|
38151
39441
|
return [];
|
|
38152
39442
|
}
|
|
38153
|
-
const entries = await
|
|
39443
|
+
const entries = await readdir18(root, { withFileTypes: true });
|
|
38154
39444
|
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => path120.join(root, entry.name));
|
|
38155
39445
|
}
|
|
38156
39446
|
function countVerificationStatuses(reports) {
|
|
@@ -38326,14 +39616,14 @@ init_service6();
|
|
|
38326
39616
|
// src/health/history.ts
|
|
38327
39617
|
init_fs();
|
|
38328
39618
|
init_util();
|
|
38329
|
-
import { readdir as
|
|
39619
|
+
import { readdir as readdir19, readFile as readFile65 } from "fs/promises";
|
|
38330
39620
|
import path121 from "path";
|
|
38331
39621
|
async function loadHistory(cwd, limit = 20) {
|
|
38332
39622
|
const dir = path121.join(dataRoot2(cwd), "history");
|
|
38333
39623
|
if (!await pathExists(dir)) {
|
|
38334
39624
|
return [];
|
|
38335
39625
|
}
|
|
38336
|
-
const files = (await
|
|
39626
|
+
const files = (await readdir19(dir)).filter((file) => file.endsWith(".json")).sort();
|
|
38337
39627
|
const points = [];
|
|
38338
39628
|
for (const file of files.slice(-limit)) {
|
|
38339
39629
|
try {
|
|
@@ -39320,7 +40610,7 @@ init_args();
|
|
|
39320
40610
|
init_validator();
|
|
39321
40611
|
init_fs();
|
|
39322
40612
|
init_store2();
|
|
39323
|
-
import { mkdir as mkdir48, readFile as readFile66, readdir as
|
|
40613
|
+
import { mkdir as mkdir48, readFile as readFile66, readdir as readdir20 } from "fs/promises";
|
|
39324
40614
|
import path124 from "path";
|
|
39325
40615
|
|
|
39326
40616
|
// src/review/types.ts
|
|
@@ -39748,7 +41038,7 @@ async function resolveReviewPackagePath(cwd, ref) {
|
|
|
39748
41038
|
if (!await pathExists(reviewsDir)) {
|
|
39749
41039
|
continue;
|
|
39750
41040
|
}
|
|
39751
|
-
for (const entry of await
|
|
41041
|
+
for (const entry of await readdir20(reviewsDir, { withFileTypes: true })) {
|
|
39752
41042
|
if (entry.isDirectory() && entry.name === ref) {
|
|
39753
41043
|
return path124.join(reviewsDir, entry.name);
|
|
39754
41044
|
}
|
|
@@ -40135,7 +41425,7 @@ var SCHEMA_REGISTRY2 = {
|
|
|
40135
41425
|
|
|
40136
41426
|
// src/standard/validate.ts
|
|
40137
41427
|
var DATE_TIME_PATTERN3 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
40138
|
-
function
|
|
41428
|
+
function isPlainObject9(value) {
|
|
40139
41429
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40140
41430
|
}
|
|
40141
41431
|
function matchesType4(value, type) {
|
|
@@ -40148,7 +41438,7 @@ function matchesType4(value, type) {
|
|
|
40148
41438
|
if (entry === "integer")
|
|
40149
41439
|
return Number.isInteger(value);
|
|
40150
41440
|
if (entry === "object")
|
|
40151
|
-
return
|
|
41441
|
+
return isPlainObject9(value);
|
|
40152
41442
|
return typeof value === entry;
|
|
40153
41443
|
});
|
|
40154
41444
|
}
|
|
@@ -40223,7 +41513,7 @@ function walk4(value, schema, valuePath, rootSchema, errors) {
|
|
|
40223
41513
|
errors.push({ path: valuePath, message: "Expected array items to be unique" });
|
|
40224
41514
|
}
|
|
40225
41515
|
}
|
|
40226
|
-
if (
|
|
41516
|
+
if (isPlainObject9(value)) {
|
|
40227
41517
|
for (const key of schema.required ?? []) {
|
|
40228
41518
|
if (!(key in value)) {
|
|
40229
41519
|
errors.push({ path: `${valuePath}.${key}`, message: "Missing required property" });
|
|
@@ -40236,7 +41526,7 @@ function walk4(value, schema, valuePath, rootSchema, errors) {
|
|
|
40236
41526
|
walk4(nested, nestedSchema, `${valuePath}.${key}`, rootSchema, errors);
|
|
40237
41527
|
} else if (schema.additionalProperties === false) {
|
|
40238
41528
|
errors.push({ path: `${valuePath}.${key}`, message: "Additional property is not allowed" });
|
|
40239
|
-
} else if (
|
|
41529
|
+
} else if (isPlainObject9(schema.additionalProperties)) {
|
|
40240
41530
|
walk4(nested, schema.additionalProperties, `${valuePath}.${key}`, rootSchema, errors);
|
|
40241
41531
|
}
|
|
40242
41532
|
}
|
|
@@ -40319,7 +41609,7 @@ async function validateWorkspace2(cwd) {
|
|
|
40319
41609
|
errors.push(issue("module-schema", `module "${key}" ${schemaError.path.replace(/^\$\.?/, "") || "(root)"}: ${schemaError.message}`, `Fix the modules.${key} entry in metaproject.json.`));
|
|
40320
41610
|
}
|
|
40321
41611
|
}
|
|
40322
|
-
if (
|
|
41612
|
+
if (isPlainObject9(manifest.paths)) {
|
|
40323
41613
|
for (const [key, value] of Object.entries(manifest.paths)) {
|
|
40324
41614
|
if (typeof value !== "string") {
|
|
40325
41615
|
continue;
|
|
@@ -40427,7 +41717,7 @@ async function runCapabilities(cwd) {
|
|
|
40427
41717
|
init_fs();
|
|
40428
41718
|
init_json();
|
|
40429
41719
|
import path128 from "path";
|
|
40430
|
-
import { readdir as
|
|
41720
|
+
import { readdir as readdir21 } from "fs/promises";
|
|
40431
41721
|
function llmsPath(cwd) {
|
|
40432
41722
|
return path128.join(cwd, ".metaproject", "llms.txt");
|
|
40433
41723
|
}
|
|
@@ -40480,7 +41770,7 @@ async function collectArtifactIndex(cwd) {
|
|
|
40480
41770
|
const walk5 = async (dir) => {
|
|
40481
41771
|
let entries;
|
|
40482
41772
|
try {
|
|
40483
|
-
entries = await
|
|
41773
|
+
entries = await readdir21(dir, { withFileTypes: true });
|
|
40484
41774
|
} catch {
|
|
40485
41775
|
return;
|
|
40486
41776
|
}
|
|
@@ -41251,7 +42541,7 @@ Usage:
|
|
|
41251
42541
|
}
|
|
41252
42542
|
|
|
41253
42543
|
// src/commands/security.ts
|
|
41254
|
-
import { mkdir as mkdir51, readdir as
|
|
42544
|
+
import { mkdir as mkdir51, readdir as readdir22, readFile as readFile72, writeFile as writeFile45 } from "fs/promises";
|
|
41255
42545
|
import path131 from "path";
|
|
41256
42546
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
41257
42547
|
init_args();
|
|
@@ -41718,7 +43008,7 @@ async function collectManifestFiles(target) {
|
|
|
41718
43008
|
}
|
|
41719
43009
|
let entries;
|
|
41720
43010
|
try {
|
|
41721
|
-
entries = await
|
|
43011
|
+
entries = await readdir22(target, { withFileTypes: true });
|
|
41722
43012
|
} catch {
|
|
41723
43013
|
return [target];
|
|
41724
43014
|
}
|
|
@@ -42574,10 +43864,10 @@ async function resolveLedgerState(ledger, checkpointPath, verifier) {
|
|
|
42574
43864
|
}
|
|
42575
43865
|
var policyRefPattern = /^\.\/.+/;
|
|
42576
43866
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
42577
|
-
var
|
|
43867
|
+
var asString6 = (value) => typeof value === "string" && value.length > 0;
|
|
42578
43868
|
var isBaselineArtifact = (artifact) => artifact.schemaVersion === "1.0" && artifact.kind === "deterministic-baseline" && isImmutableVersion2(artifact.version) && artifact.selection === "eligible-ids-in-input-order";
|
|
42579
|
-
var isCandidateArtifact = (artifact) => artifact.schemaVersion === "1.0" && artifact.kind === "offline-selection-advisor" && isImmutableVersion2(artifact.version) &&
|
|
42580
|
-
var isEvaluationReport = (report) => report.schemaVersion === "1.0" &&
|
|
43869
|
+
var isCandidateArtifact = (artifact) => artifact.schemaVersion === "1.0" && artifact.kind === "offline-selection-advisor" && isImmutableVersion2(artifact.version) && asString6(artifact.output) && typeof artifact.mutations === "boolean";
|
|
43870
|
+
var isEvaluationReport = (report) => report.schemaVersion === "1.0" && asString6(report.status) && asString6(report.baselineVersion) && asString6(report.baselineDigest) && reportHashPattern.test(report.baselineDigest) && asString6(report.candidateVersion) && asString6(report.candidateDigest) && reportHashPattern.test(report.candidateDigest) && asString6(report.corpusVersion) && asString6(report.corpusDigest) && reportHashPattern.test(report.corpusDigest) && asString6(report.reportDigest) && reportHashPattern.test(report.reportDigest) && asString6(report.sandboxProfileDigest) && reportHashPattern.test(report.sandboxProfileDigest) && isRecord3(report.train) && typeof report.train.status === "string" && typeof report.train.cases === "number" && isRecord3(report.holdout) && typeof report.holdout.status === "string" && typeof report.holdout.cases === "number" && isRecord3(report.adversarial) && typeof report.adversarial.status === "string" && typeof report.adversarial.cases === "number" && Array.isArray(report.candidateSelectedIds) && Array.isArray(report.reasons);
|
|
42581
43871
|
var isConfigRecord = (value) => typeof value.enabled === "boolean" && typeof value.killSwitch === "boolean";
|
|
42582
43872
|
async function readPinnedJson(input2) {
|
|
42583
43873
|
const ref = await resolveWorkspaceReference({ workspaceRoot: input2.workspaceRoot, kind: "artifact", uri: input2.uri });
|
|
@@ -42627,7 +43917,7 @@ async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
|
|
|
42627
43917
|
const corpusDigest = configJson.corpusDigest;
|
|
42628
43918
|
const evaluationRef = configJson.evaluationReportRef;
|
|
42629
43919
|
const evaluationDigest = configJson.evaluationDigest;
|
|
42630
|
-
if (!
|
|
43920
|
+
if (!asString6(candidateRef) || !asString6(candidateDigest) || !asString6(baselineRef) || !asString6(baselineDigest) || !asString6(corpusRef) || !asString6(corpusDigest) || !asString6(evaluationRef) || !asString6(evaluationDigest))
|
|
42631
43921
|
return canonicalFallback;
|
|
42632
43922
|
if (!workspacePathPattern3.test(candidateRef) || !workspacePathPattern3.test(baselineRef) || !workspacePathPattern3.test(corpusRef) || !workspacePathPattern3.test(evaluationRef))
|
|
42633
43923
|
return canonicalFallback;
|
|
@@ -42742,7 +44032,7 @@ async function diagnosePolicyReadiness(workspaceRoot) {
|
|
|
42742
44032
|
const corpusDigest = configJson.corpusDigest;
|
|
42743
44033
|
const evaluationRef = configJson.evaluationReportRef;
|
|
42744
44034
|
const evaluationDigest = configJson.evaluationDigest;
|
|
42745
|
-
if (!
|
|
44035
|
+
if (!asString6(candidateRef) || !asString6(candidateDigest) || !asString6(baselineRef) || !asString6(baselineDigest) || !asString6(corpusRef) || !asString6(corpusDigest) || !asString6(evaluationRef) || !asString6(evaluationDigest)) {
|
|
42746
44036
|
fail("config-pins", "pins are present but not non-empty strings");
|
|
42747
44037
|
return finalize(true, enabled, killSwitch);
|
|
42748
44038
|
}
|
|
@@ -43437,7 +44727,7 @@ function buildToolRegistry() {
|
|
|
43437
44727
|
// src/mcp/resources.ts
|
|
43438
44728
|
init_fs();
|
|
43439
44729
|
import path135 from "path";
|
|
43440
|
-
import { readdir as
|
|
44730
|
+
import { readdir as readdir23, readFile as readFile76, stat as stat7 } from "fs/promises";
|
|
43441
44731
|
var URI_PREFIX = "metaproject://";
|
|
43442
44732
|
function mimeForPath(filePath) {
|
|
43443
44733
|
if (filePath.endsWith(".json") || filePath.endsWith(".jsonl")) {
|
|
@@ -43464,7 +44754,7 @@ async function walkFiles(root) {
|
|
|
43464
44754
|
const out = [];
|
|
43465
44755
|
let entries;
|
|
43466
44756
|
try {
|
|
43467
|
-
entries = await
|
|
44757
|
+
entries = await readdir23(root, { withFileTypes: true });
|
|
43468
44758
|
} catch {
|
|
43469
44759
|
return [];
|
|
43470
44760
|
}
|
|
@@ -43486,7 +44776,7 @@ async function listArtifacts(cwd) {
|
|
|
43486
44776
|
const listings = [];
|
|
43487
44777
|
let modules;
|
|
43488
44778
|
try {
|
|
43489
|
-
modules = await
|
|
44779
|
+
modules = await readdir23(base, { withFileTypes: true });
|
|
43490
44780
|
} catch {
|
|
43491
44781
|
return [];
|
|
43492
44782
|
}
|
|
@@ -43778,7 +45068,7 @@ async function mcpCommand(args2 = [], cwd = process.cwd()) {
|
|
|
43778
45068
|
printMcpHelp();
|
|
43779
45069
|
process.exitCode = 1;
|
|
43780
45070
|
}
|
|
43781
|
-
var RUNTIME_USAGE = `<cursor|claude|opencode|generic|all>`;
|
|
45071
|
+
var RUNTIME_USAGE = `<cursor|claude|opencode|vscode|generic|all>`;
|
|
43782
45072
|
function parseRequestedRuntimes(args2, fallback) {
|
|
43783
45073
|
const runtimeArg = optionValue(args2, "--runtime") ?? fallback;
|
|
43784
45074
|
return runtimeArg.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -43862,7 +45152,7 @@ function printMcpHelp() {
|
|
|
43862
45152
|
{ flag: "--dry-run", desc: "install only: print the planned change and write nothing." }
|
|
43863
45153
|
]);
|
|
43864
45154
|
heading("Notes");
|
|
43865
|
-
console.log(` ${style.dim("`install` writes a project-local MCP client config (cursor \u2192 .cursor/mcp.json, claude \u2192 .mcp.json, opencode \u2192 opencode.json), sets modules.mcp.enabled=true, and prints a snippet for `generic`.")}`);
|
|
45155
|
+
console.log(` ${style.dim("`install` writes a project-local MCP client config (cursor \u2192 .cursor/mcp.json, claude \u2192 .mcp.json, opencode \u2192 opencode.json, vscode \u2192 .vscode/mcp.json), sets modules.mcp.enabled=true, and prints a snippet for `generic`. `vscode` is opt-in only \u2014 not included in `all`.")}`);
|
|
43866
45156
|
console.log(` ${style.dim("Requires the optional @modelcontextprotocol/sdk to serve. Disabled by default (modules.mcp.enabled=false). `install` only probes the SDK \u2014 it never installs it or opens a network connection.")}`);
|
|
43867
45157
|
}
|
|
43868
45158
|
|
|
@@ -45328,6 +46618,9 @@ function buildDefaultMaskProviders(openaiCompat) {
|
|
|
45328
46618
|
out.push({ envKey: p.envKey, baseUrl: p.baseUrl });
|
|
45329
46619
|
}
|
|
45330
46620
|
out.push({ envKey: "ANTHROPIC_API_KEY", baseUrl: "https://api.anthropic.com" });
|
|
46621
|
+
out.push({ envKey: "OPENAI_API_KEY", baseUrl: "https://api.openai.com" });
|
|
46622
|
+
out.push({ envKey: "GEMINI_API_KEY", baseUrl: "https://generativelanguage.googleapis.com" });
|
|
46623
|
+
out.push({ envKey: "GOOGLE_API_KEY", baseUrl: "https://generativelanguage.googleapis.com" });
|
|
45331
46624
|
return out;
|
|
45332
46625
|
}
|
|
45333
46626
|
function parseMaskMode(raw) {
|
|
@@ -46597,7 +47890,7 @@ async function buildApprovalContext(port, command) {
|
|
|
46597
47890
|
import { randomUUID as randomUUID20 } from "crypto";
|
|
46598
47891
|
|
|
46599
47892
|
// src/harness/tool/builtin/interactive-tools.ts
|
|
46600
|
-
import { readdir as
|
|
47893
|
+
import { readdir as readdir24 } from "fs/promises";
|
|
46601
47894
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep } from "path";
|
|
46602
47895
|
import { realpathSync as realpathSync4 } from "fs";
|
|
46603
47896
|
var MAX_READ_BYTES = 20000;
|
|
@@ -46649,7 +47942,7 @@ function builtinReadOnlyTools(root) {
|
|
|
46649
47942
|
return { output: `path escapes the project root: ${requested}`, isError: true };
|
|
46650
47943
|
}
|
|
46651
47944
|
try {
|
|
46652
|
-
const entries = await
|
|
47945
|
+
const entries = await readdir24(target, { withFileTypes: true });
|
|
46653
47946
|
const lines = entries.map((e) => e.isDirectory() ? `${e.name}/` : e.name).sort();
|
|
46654
47947
|
return { output: lines.length > 0 ? lines.join(`
|
|
46655
47948
|
`) : "(empty)", isError: false };
|
|
@@ -50330,7 +51623,7 @@ function buildClaudeResumeArgv(sessionRef, message2, input2) {
|
|
|
50330
51623
|
function asObject(value) {
|
|
50331
51624
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
50332
51625
|
}
|
|
50333
|
-
function
|
|
51626
|
+
function asString7(value) {
|
|
50334
51627
|
return typeof value === "string" ? value : undefined;
|
|
50335
51628
|
}
|
|
50336
51629
|
function asFiniteNumber(value) {
|
|
@@ -50343,16 +51636,16 @@ function truncate3(text, limit) {
|
|
|
50343
51636
|
var CLAUDE_UNMAPPED_SYSTEM_SUBTYPES = ["hook_started", "hook_response"];
|
|
50344
51637
|
var CLAUDE_UNMAPPED_LINE_TYPES = ["rate_limit_event"];
|
|
50345
51638
|
function systemEvents(obj) {
|
|
50346
|
-
const subtype =
|
|
51639
|
+
const subtype = asString7(obj.subtype);
|
|
50347
51640
|
if (subtype === "init") {
|
|
50348
|
-
const sessionRef =
|
|
51641
|
+
const sessionRef = asString7(obj.session_id);
|
|
50349
51642
|
return [sessionRef === undefined ? { kind: "child_started" } : { kind: "child_started", sessionRef }];
|
|
50350
51643
|
}
|
|
50351
51644
|
if (subtype === "api_retry") {
|
|
50352
51645
|
const attempt = asFiniteNumber(obj.attempt);
|
|
50353
51646
|
const max = asFiniteNumber(obj.max_retries);
|
|
50354
51647
|
const status = asFiniteNumber(obj.error_status);
|
|
50355
|
-
const error2 =
|
|
51648
|
+
const error2 = asString7(obj.error);
|
|
50356
51649
|
const parts = [
|
|
50357
51650
|
attempt === undefined ? "api retry" : `api retry ${attempt}${max === undefined ? "" : `/${max}`}`,
|
|
50358
51651
|
status === undefined ? undefined : `status ${status}`,
|
|
@@ -50363,32 +51656,32 @@ function systemEvents(obj) {
|
|
|
50363
51656
|
return [];
|
|
50364
51657
|
}
|
|
50365
51658
|
function toolResultDetail(content) {
|
|
50366
|
-
const direct =
|
|
51659
|
+
const direct = asString7(content);
|
|
50367
51660
|
if (direct !== undefined)
|
|
50368
51661
|
return truncate3(direct, TOOL_DETAIL_LIMIT);
|
|
50369
51662
|
if (!Array.isArray(content))
|
|
50370
51663
|
return;
|
|
50371
|
-
const text = content.map((entry) =>
|
|
51664
|
+
const text = content.map((entry) => asString7(asObject(entry)?.text)).filter((entry) => entry !== undefined).join(`
|
|
50372
51665
|
`);
|
|
50373
51666
|
return text.length === 0 ? undefined : truncate3(text, TOOL_DETAIL_LIMIT);
|
|
50374
51667
|
}
|
|
50375
51668
|
function assistantBlockEvent(block) {
|
|
50376
|
-
switch (
|
|
51669
|
+
switch (asString7(block.type)) {
|
|
50377
51670
|
case "tool_use": {
|
|
50378
|
-
const name =
|
|
51671
|
+
const name = asString7(block.name) ?? "unknown";
|
|
50379
51672
|
const detail = block.input === undefined ? undefined : truncate3(JSON.stringify(block.input), TOOL_DETAIL_LIMIT);
|
|
50380
51673
|
return detail === undefined ? { kind: "tool_call", name } : { kind: "tool_call", name, detail };
|
|
50381
51674
|
}
|
|
50382
51675
|
case "text":
|
|
50383
|
-
return { kind: "assistant_text", text:
|
|
51676
|
+
return { kind: "assistant_text", text: asString7(block.text) ?? "" };
|
|
50384
51677
|
case "thinking":
|
|
50385
|
-
return { kind: "thinking", text:
|
|
51678
|
+
return { kind: "thinking", text: asString7(block.thinking) ?? asString7(block.text) ?? "" };
|
|
50386
51679
|
default:
|
|
50387
51680
|
return;
|
|
50388
51681
|
}
|
|
50389
51682
|
}
|
|
50390
51683
|
function userBlockEvent(block) {
|
|
50391
|
-
if (
|
|
51684
|
+
if (asString7(block.type) !== "tool_result")
|
|
50392
51685
|
return;
|
|
50393
51686
|
const detail = toolResultDetail(block.content);
|
|
50394
51687
|
return detail === undefined ? { kind: "tool_result" } : { kind: "tool_result", detail };
|
|
@@ -50426,14 +51719,14 @@ function usageEvent(obj) {
|
|
|
50426
51719
|
};
|
|
50427
51720
|
}
|
|
50428
51721
|
function describeFailure(obj) {
|
|
50429
|
-
const subtype =
|
|
51722
|
+
const subtype = asString7(obj.subtype) ?? "unknown";
|
|
50430
51723
|
const parts = [`result.subtype "${subtype}"`];
|
|
50431
|
-
const text =
|
|
51724
|
+
const text = asString7(obj.result);
|
|
50432
51725
|
if (text !== undefined && text.length > 0)
|
|
50433
51726
|
parts.push(truncate3(text, TOOL_DETAIL_LIMIT));
|
|
50434
51727
|
const errors = obj.errors;
|
|
50435
51728
|
if (Array.isArray(errors)) {
|
|
50436
|
-
const flat = errors.map((entry) =>
|
|
51729
|
+
const flat = errors.map((entry) => asString7(entry)).filter((entry) => entry !== undefined);
|
|
50437
51730
|
if (flat.length > 0)
|
|
50438
51731
|
parts.push(truncate3(flat.join("; "), TOOL_DETAIL_LIMIT));
|
|
50439
51732
|
}
|
|
@@ -50443,10 +51736,10 @@ function describeFailure(obj) {
|
|
|
50443
51736
|
return parts.join(" \u2014 ");
|
|
50444
51737
|
}
|
|
50445
51738
|
function resultEvents(obj) {
|
|
50446
|
-
const subtype =
|
|
51739
|
+
const subtype = asString7(obj.subtype);
|
|
50447
51740
|
const succeeded = subtype === undefined ? obj.is_error === false : subtype === "success";
|
|
50448
51741
|
const terminal = succeeded ? (() => {
|
|
50449
|
-
const text =
|
|
51742
|
+
const text = asString7(obj.result);
|
|
50450
51743
|
return text === undefined ? { kind: "child_finished" } : { kind: "child_finished", text };
|
|
50451
51744
|
})() : { kind: "child_failed", message: describeFailure(obj) };
|
|
50452
51745
|
const usage = usageEvent(obj);
|
|
@@ -50465,7 +51758,7 @@ function parseClaudeEvents(line) {
|
|
|
50465
51758
|
const obj = asObject(parsed);
|
|
50466
51759
|
if (obj === undefined)
|
|
50467
51760
|
return [];
|
|
50468
|
-
switch (
|
|
51761
|
+
switch (asString7(obj.type)) {
|
|
50469
51762
|
case "system":
|
|
50470
51763
|
return systemEvents(obj);
|
|
50471
51764
|
case "assistant":
|
|
@@ -50495,13 +51788,13 @@ function isRecognisedClaudeLine(line) {
|
|
|
50495
51788
|
const obj = asObject(parsed);
|
|
50496
51789
|
if (obj === undefined)
|
|
50497
51790
|
return false;
|
|
50498
|
-
const type =
|
|
51791
|
+
const type = asString7(obj.type);
|
|
50499
51792
|
if (type === undefined)
|
|
50500
51793
|
return false;
|
|
50501
51794
|
if (CLAUDE_UNMAPPED_LINE_TYPES.includes(type))
|
|
50502
51795
|
return true;
|
|
50503
51796
|
if (type === "system") {
|
|
50504
|
-
const subtype =
|
|
51797
|
+
const subtype = asString7(obj.subtype) ?? "";
|
|
50505
51798
|
return subtype === "init" || subtype === "api_retry" || CLAUDE_UNMAPPED_SYSTEM_SUBTYPES.includes(subtype);
|
|
50506
51799
|
}
|
|
50507
51800
|
return type === "assistant" || type === "user" || type === "result";
|
|
@@ -50595,9 +51888,9 @@ function parseCodexEvents(line) {
|
|
|
50595
51888
|
const record = readJsonObject(line);
|
|
50596
51889
|
if (record === undefined)
|
|
50597
51890
|
return [];
|
|
50598
|
-
switch (
|
|
51891
|
+
switch (asString8(record.type)) {
|
|
50599
51892
|
case "thread.started": {
|
|
50600
|
-
const threadId =
|
|
51893
|
+
const threadId = asString8(record.thread_id);
|
|
50601
51894
|
return [threadId === undefined ? { kind: "child_started" } : { kind: "child_started", sessionRef: threadId }];
|
|
50602
51895
|
}
|
|
50603
51896
|
case "turn.started":
|
|
@@ -50615,7 +51908,7 @@ function parseCodexEvents(line) {
|
|
|
50615
51908
|
case "turn.failed":
|
|
50616
51909
|
return [{ kind: "child_failed", message: parseFailureMessage(record.error) }];
|
|
50617
51910
|
case "error":
|
|
50618
|
-
return [{ kind: "retry", message:
|
|
51911
|
+
return [{ kind: "retry", message: asString8(record.message) ?? "codex reported a non-terminal error" }];
|
|
50619
51912
|
default:
|
|
50620
51913
|
return [];
|
|
50621
51914
|
}
|
|
@@ -50636,7 +51929,7 @@ function isRecognisedCodexLine(line) {
|
|
|
50636
51929
|
const record = readJsonObject(line);
|
|
50637
51930
|
if (record === undefined)
|
|
50638
51931
|
return false;
|
|
50639
|
-
const type =
|
|
51932
|
+
const type = asString8(record.type);
|
|
50640
51933
|
return type !== undefined && RECOGNISED_TYPES.has(type);
|
|
50641
51934
|
}
|
|
50642
51935
|
var NARRATED_FAILURE_LINE = /^\s*(error\b|usage:)/i;
|
|
@@ -50696,25 +51989,25 @@ function readJsonObject(line) {
|
|
|
50696
51989
|
return;
|
|
50697
51990
|
}
|
|
50698
51991
|
}
|
|
50699
|
-
function
|
|
51992
|
+
function asString8(value) {
|
|
50700
51993
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
50701
51994
|
}
|
|
50702
|
-
function
|
|
51995
|
+
function asNumber6(value) {
|
|
50703
51996
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
50704
51997
|
}
|
|
50705
51998
|
function parseCompletedItem(raw) {
|
|
50706
51999
|
if (typeof raw !== "object" || raw === null)
|
|
50707
52000
|
return [];
|
|
50708
52001
|
const item = raw;
|
|
50709
|
-
switch (
|
|
52002
|
+
switch (asString8(item.type)) {
|
|
50710
52003
|
case "command_execution": {
|
|
50711
|
-
const command =
|
|
52004
|
+
const command = asString8(item.command);
|
|
50712
52005
|
return [
|
|
50713
52006
|
command === undefined ? { kind: "tool_call", name: "command_execution" } : { kind: "tool_call", name: "command_execution", detail: command }
|
|
50714
52007
|
];
|
|
50715
52008
|
}
|
|
50716
52009
|
case "agent_message": {
|
|
50717
|
-
const text =
|
|
52010
|
+
const text = asString8(item.text);
|
|
50718
52011
|
return text === undefined ? [] : [{ kind: "assistant_text", text }];
|
|
50719
52012
|
}
|
|
50720
52013
|
default:
|
|
@@ -50725,8 +52018,8 @@ function parseUsage(raw) {
|
|
|
50725
52018
|
if (typeof raw !== "object" || raw === null)
|
|
50726
52019
|
return;
|
|
50727
52020
|
const usage = raw;
|
|
50728
|
-
const inputTokens =
|
|
50729
|
-
const outputTokens =
|
|
52021
|
+
const inputTokens = asNumber6(usage.input_tokens);
|
|
52022
|
+
const outputTokens = asNumber6(usage.output_tokens);
|
|
50730
52023
|
if (inputTokens === undefined && outputTokens === undefined)
|
|
50731
52024
|
return;
|
|
50732
52025
|
return {
|
|
@@ -50737,11 +52030,11 @@ function parseUsage(raw) {
|
|
|
50737
52030
|
}
|
|
50738
52031
|
function parseFailureMessage(raw) {
|
|
50739
52032
|
if (typeof raw === "object" && raw !== null) {
|
|
50740
|
-
const message2 =
|
|
52033
|
+
const message2 = asString8(raw.message);
|
|
50741
52034
|
if (message2 !== undefined)
|
|
50742
52035
|
return message2;
|
|
50743
52036
|
}
|
|
50744
|
-
return
|
|
52037
|
+
return asString8(raw) ?? "codex reported a failed turn without a message";
|
|
50745
52038
|
}
|
|
50746
52039
|
function lastTerminalEvent(events) {
|
|
50747
52040
|
for (let i = events.length - 1;i >= 0; i -= 1) {
|
|
@@ -51627,7 +52920,7 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
51627
52920
|
// package.json
|
|
51628
52921
|
var package_default = {
|
|
51629
52922
|
name: "@mrciphersmith/keryx",
|
|
51630
|
-
version: "0.2.
|
|
52923
|
+
version: "0.2.50",
|
|
51631
52924
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
51632
52925
|
private: false,
|
|
51633
52926
|
publishConfig: {
|
|
@@ -52888,7 +54181,7 @@ init_store3();
|
|
|
52888
54181
|
init_proposal_lifecycle();
|
|
52889
54182
|
init_workspace_service();
|
|
52890
54183
|
import { randomUUID as randomUUID24 } from "crypto";
|
|
52891
|
-
import { readdir as
|
|
54184
|
+
import { readdir as readdir25 } from "fs/promises";
|
|
52892
54185
|
import path148 from "path";
|
|
52893
54186
|
|
|
52894
54187
|
// src/sac/lifecycle-flag.ts
|
|
@@ -53019,7 +54312,7 @@ async function isSlateEngaged(dir) {
|
|
|
53019
54312
|
if (await pathExists(path148.join(dir, "terminal-state.json")))
|
|
53020
54313
|
return true;
|
|
53021
54314
|
try {
|
|
53022
|
-
const entries = await
|
|
54315
|
+
const entries = await readdir25(path148.join(dir, "slate-archive"));
|
|
53023
54316
|
return entries.length > 0;
|
|
53024
54317
|
} catch {
|
|
53025
54318
|
return false;
|
|
@@ -53047,7 +54340,7 @@ async function readNewestUnboundCandidate(dir) {
|
|
|
53047
54340
|
const archiveDir = path148.join(dir, "slate-archive");
|
|
53048
54341
|
let entries;
|
|
53049
54342
|
try {
|
|
53050
|
-
entries = (await
|
|
54343
|
+
entries = (await readdir25(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
53051
54344
|
} catch {
|
|
53052
54345
|
return;
|
|
53053
54346
|
}
|
|
@@ -53084,7 +54377,7 @@ async function readNewestWrapUpOutcome(dir) {
|
|
|
53084
54377
|
const archiveDir = path148.join(dir, "slate-archive");
|
|
53085
54378
|
let entries;
|
|
53086
54379
|
try {
|
|
53087
|
-
entries = (await
|
|
54380
|
+
entries = (await readdir25(archiveDir)).filter((name) => name.endsWith("-wrap-up-outcome.json"));
|
|
53088
54381
|
} catch {
|
|
53089
54382
|
return;
|
|
53090
54383
|
}
|
|
@@ -54921,6 +56214,38 @@ init_providers();
|
|
|
54921
56214
|
init_patch_risk();
|
|
54922
56215
|
init_shell_config();
|
|
54923
56216
|
|
|
56217
|
+
// src/mcp-client/wire.ts
|
|
56218
|
+
var STANDARD_ELICITATION_PARAM_KEYS = new Set(["message", "requestedSchema"]);
|
|
56219
|
+
|
|
56220
|
+
// src/mcp-client/elicitation.ts
|
|
56221
|
+
init_command_risk();
|
|
56222
|
+
function extractCodexCommand(vendor) {
|
|
56223
|
+
const raw = vendor.codex_command;
|
|
56224
|
+
if (!Array.isArray(raw))
|
|
56225
|
+
return;
|
|
56226
|
+
return raw.every((entry) => typeof entry === "string") ? raw : undefined;
|
|
56227
|
+
}
|
|
56228
|
+
var SHELL_BASENAMES = new Set(["zsh", "bash", "sh", "ksh", "dash", "fish"]);
|
|
56229
|
+
var MCP_ELICITATION_TOOL_PREFIX = "mcp_elicitation:";
|
|
56230
|
+
function describeElicitationPrompt(tool, inputJson) {
|
|
56231
|
+
if (!tool.startsWith(MCP_ELICITATION_TOOL_PREFIX))
|
|
56232
|
+
return;
|
|
56233
|
+
let parsed;
|
|
56234
|
+
try {
|
|
56235
|
+
parsed = JSON.parse(inputJson);
|
|
56236
|
+
} catch {
|
|
56237
|
+
return { message: inputJson, command: undefined };
|
|
56238
|
+
}
|
|
56239
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
56240
|
+
return { message: inputJson, command: undefined };
|
|
56241
|
+
}
|
|
56242
|
+
const obj = parsed;
|
|
56243
|
+
const message2 = typeof obj.message === "string" && obj.message.trim().length > 0 ? obj.message : "codex is requesting approval for an action";
|
|
56244
|
+
const vendor = typeof obj.vendor === "object" && obj.vendor !== null ? obj.vendor : {};
|
|
56245
|
+
const command = extractCodexCommand(vendor)?.join(" ");
|
|
56246
|
+
return { message: message2, command };
|
|
56247
|
+
}
|
|
56248
|
+
|
|
54924
56249
|
// src/lib/permission-mode-config.ts
|
|
54925
56250
|
init_permission_mode();
|
|
54926
56251
|
init_config_dir();
|
|
@@ -58556,6 +59881,275 @@ ${rows.join(`
|
|
|
58556
59881
|
(none)`}
|
|
58557
59882
|
`;
|
|
58558
59883
|
}
|
|
59884
|
+
async function selectSearchProviderAndReport(controller, onSystem, providerId) {
|
|
59885
|
+
const result = await controller.select(providerId);
|
|
59886
|
+
if (!result.ok) {
|
|
59887
|
+
if (result.reason === "not-configured") {
|
|
59888
|
+
onSystem?.(`Cannot select '${providerId}': provider is not configured.
|
|
59889
|
+
`);
|
|
59890
|
+
} else if (result.reason === "not-connected") {
|
|
59891
|
+
onSystem?.(`Cannot select '${providerId}': provider is not connected (run /search-provider ${providerId} <params> to test).
|
|
59892
|
+
`);
|
|
59893
|
+
} else {
|
|
59894
|
+
onSystem?.(`Cannot select '${providerId}': ${result.reason}.
|
|
59895
|
+
`);
|
|
59896
|
+
}
|
|
59897
|
+
return;
|
|
59898
|
+
}
|
|
59899
|
+
onSystem?.(`Search provider '${providerId}' selected.
|
|
59900
|
+
`);
|
|
59901
|
+
}
|
|
59902
|
+
function promptSearchFieldStep(otui, r, field3, value) {
|
|
59903
|
+
return new Promise((resolve3) => {
|
|
59904
|
+
const box = overlayBox(otui, r, "search-field-picker");
|
|
59905
|
+
r.root.add(box);
|
|
59906
|
+
box.add(new otui.TextRenderable(r, { id: "sf-title", content: otui.t`${otui.bold(field3.label)} ${otui.dim(`${field3.required ? "required" : "optional"} \xB7 Enter \xB7 Esc to go back`)}` }));
|
|
59907
|
+
const input2 = new otui.InputRenderable(r, { id: "sf-input", value, marginTop: 1 });
|
|
59908
|
+
box.add(input2);
|
|
59909
|
+
input2.focus();
|
|
59910
|
+
const cleanup = () => {
|
|
59911
|
+
unsub();
|
|
59912
|
+
input2.blur();
|
|
59913
|
+
r.root.remove(box);
|
|
59914
|
+
};
|
|
59915
|
+
const unsub = onKeypress4(r, (key) => {
|
|
59916
|
+
if (key.name === "escape") {
|
|
59917
|
+
cleanup();
|
|
59918
|
+
resolve3({ kind: "back" });
|
|
59919
|
+
key.preventDefault();
|
|
59920
|
+
key.stopPropagation();
|
|
59921
|
+
}
|
|
59922
|
+
});
|
|
59923
|
+
input2.on(otui.InputRenderableEvents.ENTER, () => {
|
|
59924
|
+
const entered = input2.value.trim();
|
|
59925
|
+
cleanup();
|
|
59926
|
+
resolve3({ kind: "value", value: entered });
|
|
59927
|
+
});
|
|
59928
|
+
});
|
|
59929
|
+
}
|
|
59930
|
+
function promptSearchCredentialStep(otui, r, opts) {
|
|
59931
|
+
return new Promise((resolve3) => {
|
|
59932
|
+
const box = overlayBox(otui, r, "search-credential-picker");
|
|
59933
|
+
r.root.add(box);
|
|
59934
|
+
box.add(new otui.TextRenderable(r, { id: "sc-title", content: otui.t`${otui.bold(`Paste your ${opts.label}`)} ${otui.dim("(Enter \xB7 Esc to go back)")}` }));
|
|
59935
|
+
box.add(new otui.TextRenderable(r, {
|
|
59936
|
+
id: "sc-note",
|
|
59937
|
+
content: otui.t`${otui.dim("Saved to your keryx config dir (owner-only, 0600)")}`,
|
|
59938
|
+
marginTop: 1
|
|
59939
|
+
}));
|
|
59940
|
+
const keyInput = new otui.InputRenderable(r, { id: "sc-input", placeholder: "...", marginTop: 1 });
|
|
59941
|
+
box.add(keyInput);
|
|
59942
|
+
keyInput.focus();
|
|
59943
|
+
const cleanup = () => {
|
|
59944
|
+
unsub();
|
|
59945
|
+
keyInput.blur();
|
|
59946
|
+
r.root.remove(box);
|
|
59947
|
+
};
|
|
59948
|
+
const unsub = onKeypress4(r, (key) => {
|
|
59949
|
+
if (key.name === "escape") {
|
|
59950
|
+
cleanup();
|
|
59951
|
+
resolve3({ kind: "back" });
|
|
59952
|
+
key.preventDefault();
|
|
59953
|
+
key.stopPropagation();
|
|
59954
|
+
}
|
|
59955
|
+
});
|
|
59956
|
+
keyInput.on(otui.InputRenderableEvents.ENTER, () => {
|
|
59957
|
+
const value = keyInput.value.trim();
|
|
59958
|
+
cleanup();
|
|
59959
|
+
resolve3(value.length > 0 ? { kind: "key", value } : { kind: "skip" });
|
|
59960
|
+
});
|
|
59961
|
+
});
|
|
59962
|
+
}
|
|
59963
|
+
function promptSetActiveProviderStep(otui, r) {
|
|
59964
|
+
return new Promise((resolve3) => {
|
|
59965
|
+
const box = overlayBox(otui, r, "search-active-picker");
|
|
59966
|
+
r.root.add(box);
|
|
59967
|
+
box.add(new otui.TextRenderable(r, { id: "sa-title", content: otui.t`${otui.bold("Set as active provider after a successful test?")} ${otui.dim("(\u2191/\u2193, Enter \xB7 Esc to go back)")}` }));
|
|
59968
|
+
const select = new otui.SelectRenderable(r, {
|
|
59969
|
+
id: "sa-select",
|
|
59970
|
+
width: 60,
|
|
59971
|
+
height: selectBoxHeight(2, true),
|
|
59972
|
+
options: [
|
|
59973
|
+
{ name: "Yes", description: "select it once the test passes" },
|
|
59974
|
+
{ name: "No", description: "leave it configured but inactive" }
|
|
59975
|
+
],
|
|
59976
|
+
selectedTextColor: "#ffd166"
|
|
59977
|
+
});
|
|
59978
|
+
box.add(select);
|
|
59979
|
+
select.focus();
|
|
59980
|
+
const cleanup = () => {
|
|
59981
|
+
unsub();
|
|
59982
|
+
select.blur();
|
|
59983
|
+
r.root.remove(box);
|
|
59984
|
+
};
|
|
59985
|
+
const unsub = onKeypress4(r, (key) => {
|
|
59986
|
+
if (key.name === "escape") {
|
|
59987
|
+
cleanup();
|
|
59988
|
+
resolve3(undefined);
|
|
59989
|
+
key.preventDefault();
|
|
59990
|
+
key.stopPropagation();
|
|
59991
|
+
}
|
|
59992
|
+
});
|
|
59993
|
+
select.on(otui.SelectRenderableEvents.ITEM_SELECTED, () => {
|
|
59994
|
+
const chosen = select.getSelectedOption();
|
|
59995
|
+
cleanup();
|
|
59996
|
+
resolve3(chosen === null ? undefined : chosen.name === "Yes");
|
|
59997
|
+
});
|
|
59998
|
+
});
|
|
59999
|
+
}
|
|
60000
|
+
function pickSearchProviderStep(otui, r, providers) {
|
|
60001
|
+
return new Promise((resolve3) => {
|
|
60002
|
+
const box = overlayBox(otui, r, "search-provider-picker");
|
|
60003
|
+
r.root.add(box);
|
|
60004
|
+
box.add(new otui.TextRenderable(r, { id: "spp-title", content: otui.t`${otui.bold("Select a search provider")} ${otui.dim("(\u2191/\u2193, Enter \xB7 Esc to cancel)")}` }));
|
|
60005
|
+
const labelOf = (p) => `${p.id} (${p.displayName})`;
|
|
60006
|
+
const select = new otui.SelectRenderable(r, {
|
|
60007
|
+
id: "spp-select",
|
|
60008
|
+
width: 60,
|
|
60009
|
+
height: selectBoxHeight(providers.length, true),
|
|
60010
|
+
showScrollIndicator: true,
|
|
60011
|
+
options: providers.map((p) => ({ name: labelOf(p), description: p.kind })),
|
|
60012
|
+
selectedTextColor: "#ffd166"
|
|
60013
|
+
});
|
|
60014
|
+
box.add(select);
|
|
60015
|
+
select.focus();
|
|
60016
|
+
const cleanup = () => {
|
|
60017
|
+
unsub();
|
|
60018
|
+
select.blur();
|
|
60019
|
+
r.root.remove(box);
|
|
60020
|
+
};
|
|
60021
|
+
const unsub = onKeypress4(r, (key) => {
|
|
60022
|
+
if (key.name === "escape") {
|
|
60023
|
+
cleanup();
|
|
60024
|
+
resolve3(undefined);
|
|
60025
|
+
key.preventDefault();
|
|
60026
|
+
key.stopPropagation();
|
|
60027
|
+
}
|
|
60028
|
+
});
|
|
60029
|
+
select.on(otui.SelectRenderableEvents.ITEM_SELECTED, () => {
|
|
60030
|
+
const chosen = select.getSelectedOption();
|
|
60031
|
+
cleanup();
|
|
60032
|
+
resolve3(chosen === null ? undefined : providers.find((p) => labelOf(p) === chosen.name));
|
|
60033
|
+
});
|
|
60034
|
+
});
|
|
60035
|
+
}
|
|
60036
|
+
async function runSearchProviderFieldsStep(otui, r, provider, seed) {
|
|
60037
|
+
const subSteps = [
|
|
60038
|
+
...provider.fields.map((field3) => ({ kind: "field", field: field3 })),
|
|
60039
|
+
...provider.credentialSchema.required ? [{ kind: "credential" }] : [],
|
|
60040
|
+
{ kind: "toggle" }
|
|
60041
|
+
];
|
|
60042
|
+
const fields = { ...seed.fields };
|
|
60043
|
+
let credential2 = seed.credential;
|
|
60044
|
+
let setActive = seed.setActive;
|
|
60045
|
+
let index = 0;
|
|
60046
|
+
while (index < subSteps.length) {
|
|
60047
|
+
const step = subSteps[index];
|
|
60048
|
+
if (step === undefined)
|
|
60049
|
+
break;
|
|
60050
|
+
if (step.kind === "field") {
|
|
60051
|
+
const result = await promptSearchFieldStep(otui, r, step.field, fields[step.field.id] ?? step.field.defaultValue ?? "");
|
|
60052
|
+
if (result.kind === "back") {
|
|
60053
|
+
index -= 1;
|
|
60054
|
+
if (index < 0)
|
|
60055
|
+
return { kind: "back" };
|
|
60056
|
+
continue;
|
|
60057
|
+
}
|
|
60058
|
+
fields[step.field.id] = result.value;
|
|
60059
|
+
index += 1;
|
|
60060
|
+
continue;
|
|
60061
|
+
}
|
|
60062
|
+
if (step.kind === "credential") {
|
|
60063
|
+
const result = await promptSearchCredentialStep(otui, r, {
|
|
60064
|
+
label: provider.credentialSchema.label ?? `${provider.displayName} credential`
|
|
60065
|
+
});
|
|
60066
|
+
if (result.kind === "back") {
|
|
60067
|
+
index -= 1;
|
|
60068
|
+
if (index < 0)
|
|
60069
|
+
return { kind: "back" };
|
|
60070
|
+
continue;
|
|
60071
|
+
}
|
|
60072
|
+
credential2 = result.kind === "key" ? result.value : undefined;
|
|
60073
|
+
index += 1;
|
|
60074
|
+
continue;
|
|
60075
|
+
}
|
|
60076
|
+
const toggle = await promptSetActiveProviderStep(otui, r);
|
|
60077
|
+
if (toggle === undefined) {
|
|
60078
|
+
index -= 1;
|
|
60079
|
+
if (index < 0)
|
|
60080
|
+
return { kind: "back" };
|
|
60081
|
+
continue;
|
|
60082
|
+
}
|
|
60083
|
+
setActive = toggle;
|
|
60084
|
+
index += 1;
|
|
60085
|
+
}
|
|
60086
|
+
return { kind: "done", fields, credential: credential2, setActive };
|
|
60087
|
+
}
|
|
60088
|
+
function runSearchProviderTestStep(otui, r, controller, provider, fields, credential2, setActive) {
|
|
60089
|
+
return new Promise((resolve3) => {
|
|
60090
|
+
const box = overlayBox(otui, r, "search-test-picker");
|
|
60091
|
+
r.root.add(box);
|
|
60092
|
+
const status = new otui.TextRenderable(r, { id: "st-title", content: otui.t`${otui.bold(`Testing '${provider.id}'`)} ${otui.dim("...")}` });
|
|
60093
|
+
box.add(status);
|
|
60094
|
+
let settled;
|
|
60095
|
+
const cleanup = () => {
|
|
60096
|
+
unsub();
|
|
60097
|
+
r.root.remove(box);
|
|
60098
|
+
};
|
|
60099
|
+
const unsub = onKeypress4(r, (key) => {
|
|
60100
|
+
if (settled === "failure" && key.name === "escape") {
|
|
60101
|
+
cleanup();
|
|
60102
|
+
resolve3("retry");
|
|
60103
|
+
key.preventDefault();
|
|
60104
|
+
key.stopPropagation();
|
|
60105
|
+
} else if (settled === "success" && (key.name === "return" || key.name === "linefeed" || key.name === "kpenter")) {
|
|
60106
|
+
cleanup();
|
|
60107
|
+
resolve3("done");
|
|
60108
|
+
key.preventDefault();
|
|
60109
|
+
key.stopPropagation();
|
|
60110
|
+
}
|
|
60111
|
+
});
|
|
60112
|
+
(async () => {
|
|
60113
|
+
controller.configure(provider.id, { ...provider.defaults, ...fields }, credential2);
|
|
60114
|
+
const tested = await controller.test(provider.id);
|
|
60115
|
+
if (!tested.ok) {
|
|
60116
|
+
settled = "failure";
|
|
60117
|
+
const reason = tested.reason === "missing-credential" ? "missing credential" : "connection validation failed";
|
|
60118
|
+
status.content = otui.t`${otui.red("\u2717")} ${otui.bold(`'${provider.id}' test failed: ${reason}`)} ${otui.dim("(Esc to go back and retry)")}`;
|
|
60119
|
+
return;
|
|
60120
|
+
}
|
|
60121
|
+
settled = "success";
|
|
60122
|
+
if (!setActive) {
|
|
60123
|
+
status.content = otui.t`${otui.green("\u2713")} ${otui.bold(`'${provider.id}' configured and tested successfully`)} ${otui.dim("(Enter to close)")}`;
|
|
60124
|
+
return;
|
|
60125
|
+
}
|
|
60126
|
+
const selected = await controller.select(provider.id);
|
|
60127
|
+
status.content = selected.ok ? otui.t`${otui.green("\u2713")} ${otui.bold(`'${provider.id}' configured, tested, and set as active`)} ${otui.dim("(Enter to close)")}` : otui.t`${otui.green("\u2713")} ${otui.bold(`'${provider.id}' configured and tested`)} ${otui.dim(`but could not be set active (${selected.reason ?? "unknown"})`)} ${otui.dim("(Enter to close)")}`;
|
|
60128
|
+
})();
|
|
60129
|
+
});
|
|
60130
|
+
}
|
|
60131
|
+
async function searchProviderWizardInTui(otui, r, controller) {
|
|
60132
|
+
const providers = controller.configurable();
|
|
60133
|
+
providerLoop:
|
|
60134
|
+
while (true) {
|
|
60135
|
+
const provider = await pickSearchProviderStep(otui, r, providers);
|
|
60136
|
+
if (provider === undefined) {
|
|
60137
|
+
return;
|
|
60138
|
+
}
|
|
60139
|
+
let seed = { fields: { ...provider.defaults }, credential: undefined, setActive: false };
|
|
60140
|
+
while (true) {
|
|
60141
|
+
const step2 = await runSearchProviderFieldsStep(otui, r, provider, seed);
|
|
60142
|
+
if (step2.kind === "back") {
|
|
60143
|
+
continue providerLoop;
|
|
60144
|
+
}
|
|
60145
|
+
seed = { fields: step2.fields, credential: step2.credential, setActive: step2.setActive };
|
|
60146
|
+
const result = await runSearchProviderTestStep(otui, r, controller, provider, seed.fields, seed.credential, seed.setActive);
|
|
60147
|
+
if (result === "done") {
|
|
60148
|
+
return;
|
|
60149
|
+
}
|
|
60150
|
+
}
|
|
60151
|
+
}
|
|
60152
|
+
}
|
|
58559
60153
|
function promptBaseUrlStep(otui, r, label, baseUrl2) {
|
|
58560
60154
|
return new Promise((resolve3) => {
|
|
58561
60155
|
const box = overlayBox(otui, r, "base-url-picker");
|
|
@@ -59332,6 +60926,51 @@ async function launchTuiAgentShell(opts) {
|
|
|
59332
60926
|
}));
|
|
59333
60927
|
return id === "allow";
|
|
59334
60928
|
}
|
|
60929
|
+
if (tool.startsWith(MCP_ELICITATION_TOOL_PREFIX)) {
|
|
60930
|
+
const described = describeElicitationPrompt(tool, inputJson) ?? { message: inputJson, command: undefined };
|
|
60931
|
+
transcript.add(new otui.TextRenderable(r, {
|
|
60932
|
+
id: `ap${uid++}`,
|
|
60933
|
+
content: otui.t`${otui.yellow("\u2699 codex is requesting approval")}`
|
|
60934
|
+
}));
|
|
60935
|
+
transcript.add(new otui.TextRenderable(r, { id: `ap${uid++}`, content: otui.t`${otui.dim(described.message)}` }));
|
|
60936
|
+
if (described.command !== undefined) {
|
|
60937
|
+
transcript.add(new otui.TextRenderable(r, {
|
|
60938
|
+
id: `ap${uid++}`,
|
|
60939
|
+
content: otui.t`${otui.dim(`command: ${described.command}`)}`
|
|
60940
|
+
}));
|
|
60941
|
+
}
|
|
60942
|
+
if (meta?.destructive === true) {
|
|
60943
|
+
transcript.add(new otui.TextRenderable(r, {
|
|
60944
|
+
id: `ap${uid++}`,
|
|
60945
|
+
content: otui.t`${otui.yellow("deletes a file, touches .git/, or touches many files in one call")}`
|
|
60946
|
+
}));
|
|
60947
|
+
}
|
|
60948
|
+
if (meta?.credentials === true) {
|
|
60949
|
+
transcript.add(new otui.TextRenderable(r, {
|
|
60950
|
+
id: `ap${uid++}`,
|
|
60951
|
+
content: otui.t`${otui.yellow("touches the agent's own permission/credential files")}`
|
|
60952
|
+
}));
|
|
60953
|
+
}
|
|
60954
|
+
chrome.hideMenu();
|
|
60955
|
+
setMainAgent("blocked", "approval");
|
|
60956
|
+
const elicitationSubtitle = described.message.length > 80 ? `${described.message.slice(0, 77)}\u2026` : described.message;
|
|
60957
|
+
const id = await showComposerChoice(otui, r, chrome.dock, {
|
|
60958
|
+
title: "Approve codex elicitation?",
|
|
60959
|
+
subtitle: elicitationSubtitle,
|
|
60960
|
+
cancelId: "deny",
|
|
60961
|
+
options: [
|
|
60962
|
+
{ id: "allow", label: "Approve", description: "codex proceeds with this action", recommended: true },
|
|
60963
|
+
{ id: "deny", label: "Deny", description: "codex's action is refused" }
|
|
60964
|
+
]
|
|
60965
|
+
});
|
|
60966
|
+
input2.focus();
|
|
60967
|
+
setMainAgent("running", id === "allow" ? "write" : "denied");
|
|
60968
|
+
transcript.add(new otui.TextRenderable(r, {
|
|
60969
|
+
id: `ap${uid++}`,
|
|
60970
|
+
content: id === "allow" ? otui.t`${otui.green("\u25C7 codex elicitation approved")}` : otui.t`${otui.red("\u25C7 codex elicitation denied")}`
|
|
60971
|
+
}));
|
|
60972
|
+
return id === "allow";
|
|
60973
|
+
}
|
|
59335
60974
|
const ev = evaluateShellApproval({
|
|
59336
60975
|
inputJson,
|
|
59337
60976
|
...meta !== undefined ? { meta } : {},
|
|
@@ -60459,7 +62098,8 @@ Staying in the current session.
|
|
|
60459
62098
|
const args2 = parseSearchProviderArgs(line.slice(16));
|
|
60460
62099
|
const all = searchProviderController.configurable();
|
|
60461
62100
|
if (args2.providerId === undefined) {
|
|
60462
|
-
|
|
62101
|
+
await chrome.withOverlay(() => searchProviderWizardInTui(otui, r, searchProviderController));
|
|
62102
|
+
input2.focus();
|
|
60463
62103
|
return;
|
|
60464
62104
|
}
|
|
60465
62105
|
const descriptor = all.find((candidate) => candidate.id === args2.providerId);
|
|
@@ -60488,11 +62128,18 @@ Staying in the current session.
|
|
|
60488
62128
|
const providerId = args2.providerId;
|
|
60489
62129
|
if (providerId === undefined) {
|
|
60490
62130
|
const selectable = searchProviderController.selectable();
|
|
60491
|
-
io.onSystem?.(describeSearchProviderList("Connected search providers (use /search-connect <id> to select):", selectable));
|
|
60492
62131
|
if (selectable.length === 0) {
|
|
62132
|
+
io.onSystem?.(describeSearchProviderList("Connected search providers (use /search-connect <id> to select):", selectable));
|
|
60493
62133
|
io.onSystem?.(`No connected search providers found. Run /search-provider first.
|
|
60494
62134
|
`);
|
|
62135
|
+
return;
|
|
62136
|
+
}
|
|
62137
|
+
const picked = await chrome.withOverlay(() => pickSearchProviderStep(otui, r, selectable));
|
|
62138
|
+
input2.focus();
|
|
62139
|
+
if (picked === undefined) {
|
|
62140
|
+
return;
|
|
60495
62141
|
}
|
|
62142
|
+
await selectSearchProviderAndReport(searchProviderController, io.onSystem, picked.id);
|
|
60496
62143
|
return;
|
|
60497
62144
|
}
|
|
60498
62145
|
const normalizedProviderId = searchProviderController.configurable().find((candidate) => candidate.id === providerId)?.id;
|
|
@@ -60501,22 +62148,7 @@ Staying in the current session.
|
|
|
60501
62148
|
`);
|
|
60502
62149
|
return;
|
|
60503
62150
|
}
|
|
60504
|
-
|
|
60505
|
-
if (!result.ok) {
|
|
60506
|
-
if (result.reason === "not-configured") {
|
|
60507
|
-
io.onSystem?.(`Cannot select '${providerId}': provider is not configured.
|
|
60508
|
-
`);
|
|
60509
|
-
} else if (result.reason === "not-connected") {
|
|
60510
|
-
io.onSystem?.(`Cannot select '${providerId}': provider is not connected (run /search-provider ${providerId} <params> to test).
|
|
60511
|
-
`);
|
|
60512
|
-
} else {
|
|
60513
|
-
io.onSystem?.(`Cannot select '${providerId}': ${result.reason}.
|
|
60514
|
-
`);
|
|
60515
|
-
}
|
|
60516
|
-
return;
|
|
60517
|
-
}
|
|
60518
|
-
io.onSystem?.(`Search provider '${providerId}' selected.
|
|
60519
|
-
`);
|
|
62151
|
+
await selectSearchProviderAndReport(searchProviderController, io.onSystem, normalizedProviderId);
|
|
60520
62152
|
})();
|
|
60521
62153
|
return;
|
|
60522
62154
|
}
|
|
@@ -61256,6 +62888,8 @@ init_guard2();
|
|
|
61256
62888
|
init_providers();
|
|
61257
62889
|
var DEFAULT_OLLAMA_BASE_URL = "http://localhost:11434";
|
|
61258
62890
|
var ANTHROPIC_MODELS = ["claude-sonnet-5", "claude-opus-4-8", "claude-haiku-4-5"];
|
|
62891
|
+
var OPENAI_MODELS = ["gpt-5.6", "gpt-5.6-terra", "gpt-5.6-luna"];
|
|
62892
|
+
var GEMINI_MODELS = ["gemini-3.7-flash", "gemini-2.5-pro", "gemini-2.5-flash-lite"];
|
|
61259
62893
|
var FAKE_MODELS = ["fake-echo"];
|
|
61260
62894
|
function isEmbeddingModel(model) {
|
|
61261
62895
|
const name = typeof model.name === "string" ? model.name.toLowerCase() : "";
|
|
@@ -61316,6 +62950,14 @@ async function detectProviders(deps) {
|
|
|
61316
62950
|
if (typeof anthropicKey === "string" && anthropicKey.length > 0) {
|
|
61317
62951
|
detected.push({ name: "anthropic", models: [...ANTHROPIC_MODELS] });
|
|
61318
62952
|
}
|
|
62953
|
+
const openaiKey = deps.env.OPENAI_API_KEY;
|
|
62954
|
+
if (typeof openaiKey === "string" && openaiKey.length > 0) {
|
|
62955
|
+
detected.push({ name: "openai", models: [...OPENAI_MODELS] });
|
|
62956
|
+
}
|
|
62957
|
+
const geminiKey = deps.env.GEMINI_API_KEY ?? deps.env.GOOGLE_API_KEY;
|
|
62958
|
+
if (typeof geminiKey === "string" && geminiKey.length > 0) {
|
|
62959
|
+
detected.push({ name: "gemini", models: [...GEMINI_MODELS] });
|
|
62960
|
+
}
|
|
61319
62961
|
for (const p of OPENAI_COMPAT_PROVIDERS) {
|
|
61320
62962
|
if (!isProviderPlatformSupported(p, platform)) {
|
|
61321
62963
|
continue;
|
|
@@ -62154,6 +63796,37 @@ ${GUTTER}${style.dim("[y/N] ")}`);
|
|
|
62154
63796
|
const approved2 = /^y(es)?$/i.test(answer2);
|
|
62155
63797
|
out(approved2 ? style.green(`approved
|
|
62156
63798
|
`) : style.red(`denied
|
|
63799
|
+
`));
|
|
63800
|
+
if (!approved2) {
|
|
63801
|
+
return false;
|
|
63802
|
+
}
|
|
63803
|
+
return meta?.fingerprint !== undefined ? { approved: true, fingerprint: meta.fingerprint } : true;
|
|
63804
|
+
}
|
|
63805
|
+
if (tool.startsWith(MCP_ELICITATION_TOOL_PREFIX)) {
|
|
63806
|
+
const described = describeElicitationPrompt(tool, input2) ?? { message: input2, command: undefined };
|
|
63807
|
+
out(`
|
|
63808
|
+
${GUTTER}${style.yellow("Approve codex elicitation?")}
|
|
63809
|
+
`);
|
|
63810
|
+
out(`${indentBlock(described.message, GUTTER)}
|
|
63811
|
+
`);
|
|
63812
|
+
if (described.command !== undefined) {
|
|
63813
|
+
out(`${GUTTER}${style.dim(`command: ${described.command}`)}
|
|
63814
|
+
`);
|
|
63815
|
+
}
|
|
63816
|
+
if (meta?.destructive === true) {
|
|
63817
|
+
out(`${GUTTER}${style.yellow("deletes a file, touches .git/, or touches many files in one call")}
|
|
63818
|
+
`);
|
|
63819
|
+
}
|
|
63820
|
+
if (meta?.credentials === true) {
|
|
63821
|
+
out(`${GUTTER}${style.yellow("touches the agent's own permission/credential files")}
|
|
63822
|
+
`);
|
|
63823
|
+
}
|
|
63824
|
+
out(`
|
|
63825
|
+
${GUTTER}${style.dim("[y/N] ")}`);
|
|
63826
|
+
const answer2 = (await readLine() ?? "").trim();
|
|
63827
|
+
const approved2 = /^y(es)?$/i.test(answer2);
|
|
63828
|
+
out(approved2 ? style.green(`approved
|
|
63829
|
+
`) : style.red(`denied
|
|
62157
63830
|
`));
|
|
62158
63831
|
if (!approved2) {
|
|
62159
63832
|
return false;
|
|
@@ -65129,7 +66802,7 @@ function printHelp17() {
|
|
|
65129
66802
|
|
|
65130
66803
|
// src/commands/update.ts
|
|
65131
66804
|
import { spawn as spawn5 } from "child_process";
|
|
65132
|
-
import { chmod as chmod4, mkdir as mkdir55, readFile as readFile79, readdir as
|
|
66805
|
+
import { chmod as chmod4, mkdir as mkdir55, readFile as readFile79, readdir as readdir26, writeFile as writeFile49 } from "fs/promises";
|
|
65133
66806
|
import { access as access4, constants as constants2, existsSync as existsSync30 } from "fs";
|
|
65134
66807
|
import path156 from "path";
|
|
65135
66808
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
@@ -65481,7 +67154,7 @@ async function collectTasksDashboardData(metaprojectRoot) {
|
|
|
65481
67154
|
}
|
|
65482
67155
|
let dirEntries;
|
|
65483
67156
|
try {
|
|
65484
|
-
dirEntries = (await
|
|
67157
|
+
dirEntries = (await readdir26(flowsRoot2, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^\d{3}-/.test(entry.name)).map((entry) => entry.name).sort();
|
|
65485
67158
|
} catch {
|
|
65486
67159
|
return null;
|
|
65487
67160
|
}
|
|
@@ -65775,7 +67448,7 @@ async function collectMarkdownPages(root, hrefPrefix) {
|
|
|
65775
67448
|
return pages;
|
|
65776
67449
|
}
|
|
65777
67450
|
async function listMarkdownFiles(root) {
|
|
65778
|
-
const entries = await
|
|
67451
|
+
const entries = await readdir26(root, { withFileTypes: true });
|
|
65779
67452
|
const files = [];
|
|
65780
67453
|
for (const entry of entries) {
|
|
65781
67454
|
const fullPath = path156.join(root, entry.name);
|
|
@@ -66215,7 +67888,7 @@ async function runPostUpdateHooks(projectRoot) {
|
|
|
66215
67888
|
if (!await pathExists(hooksDir)) {
|
|
66216
67889
|
return;
|
|
66217
67890
|
}
|
|
66218
|
-
const entries = (await
|
|
67891
|
+
const entries = (await readdir26(hooksDir)).sort();
|
|
66219
67892
|
for (const entry of entries) {
|
|
66220
67893
|
const hookPath = path156.join(hooksDir, entry);
|
|
66221
67894
|
try {
|
|
@@ -67921,7 +69594,7 @@ function oracleRates(score) {
|
|
|
67921
69594
|
rates.recall = deriveRate(score.truePositives, score.goldSize, ORACLE_RELIABILITY);
|
|
67922
69595
|
return Object.keys(rates).length > 0 ? rates : undefined;
|
|
67923
69596
|
}
|
|
67924
|
-
var
|
|
69597
|
+
var DEFAULT_MODEL5 = "gdgraph-oracle";
|
|
67925
69598
|
var GOLD_KIND_LABELS = {
|
|
67926
69599
|
"co-change": "co-change prediction",
|
|
67927
69600
|
dependency: "graph correctness"
|
|
@@ -67960,7 +69633,7 @@ function scoreGoldRun(input2, named, options = {}) {
|
|
|
67960
69633
|
variant: "baseline",
|
|
67961
69634
|
run_id: `${taskId}#1`,
|
|
67962
69635
|
ladder: options.ladder ?? "metastore",
|
|
67963
|
-
model: options.model ??
|
|
69636
|
+
model: options.model ?? DEFAULT_MODEL5,
|
|
67964
69637
|
cacheState: options.cacheState ?? "unknown",
|
|
67965
69638
|
leakageAssertion: options.leakageAssertion ?? "not-applicable",
|
|
67966
69639
|
caseKind: "deterministic",
|
|
@@ -68204,7 +69877,7 @@ function buildEvidenceBundle(input2, options = {}) {
|
|
|
68204
69877
|
run: {
|
|
68205
69878
|
target: score.target,
|
|
68206
69879
|
variant,
|
|
68207
|
-
model: options.model ??
|
|
69880
|
+
model: options.model ?? DEFAULT_MODEL5,
|
|
68208
69881
|
seed,
|
|
68209
69882
|
cacheState: options.cacheState ?? "unknown",
|
|
68210
69883
|
startedAt: timestamp,
|
|
@@ -69403,6 +71076,6 @@ if (import.meta.main) {
|
|
|
69403
71076
|
});
|
|
69404
71077
|
}
|
|
69405
71078
|
export {
|
|
69406
|
-
|
|
69407
|
-
|
|
71079
|
+
CLI_ROUTES,
|
|
71080
|
+
main
|
|
69408
71081
|
};
|