snipara-companion 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +25 -2
- package/dist/index.js +269 -4
- package/docs/FULL_REFERENCE.md +56 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3365,6 +3365,7 @@ interface AdaptiveWorkProfile {
|
|
|
3365
3365
|
contextBudget: string;
|
|
3366
3366
|
reasoningDepth: string;
|
|
3367
3367
|
evidenceRequirements?: string[];
|
|
3368
|
+
preferredProfileStrengths?: string[];
|
|
3368
3369
|
notes?: string[];
|
|
3369
3370
|
}
|
|
3370
3371
|
interface AdaptiveModelRequirements {
|
|
@@ -3377,6 +3378,7 @@ interface AdaptiveModelRequirements {
|
|
|
3377
3378
|
capabilities: string[];
|
|
3378
3379
|
forbiddenCapabilities: string[];
|
|
3379
3380
|
writeScope: string[];
|
|
3381
|
+
structuredOutputRequired?: boolean;
|
|
3380
3382
|
preferredEndpointTypes?: string[];
|
|
3381
3383
|
allowedEndpointTypes?: string[];
|
|
3382
3384
|
catalogLimit?: number;
|
|
@@ -3394,13 +3396,13 @@ interface AdaptiveRoutingCard {
|
|
|
3394
3396
|
requirements: AdaptiveModelRequirements;
|
|
3395
3397
|
recommendedWorkerClass: string;
|
|
3396
3398
|
costEstimate: AdaptiveRoutingCostEstimate;
|
|
3397
|
-
humanApprovalRequired:
|
|
3399
|
+
humanApprovalRequired: boolean;
|
|
3398
3400
|
fallback: "main_agent";
|
|
3399
3401
|
reasons: string[];
|
|
3400
3402
|
warnings: string[];
|
|
3401
3403
|
}
|
|
3402
3404
|
interface AdaptiveRoutingGatewayStatus {
|
|
3403
|
-
source: "hosted_mcp";
|
|
3405
|
+
source: "hosted_mcp" | "local_orchestrator";
|
|
3404
3406
|
success: boolean;
|
|
3405
3407
|
resolutionStatus?: string;
|
|
3406
3408
|
candidateCount: number;
|
|
@@ -3409,14 +3411,32 @@ interface AdaptiveRoutingGatewayStatus {
|
|
|
3409
3411
|
}
|
|
3410
3412
|
interface AdaptiveRoutingRuntimeCatalog {
|
|
3411
3413
|
version?: string;
|
|
3414
|
+
source?: string;
|
|
3415
|
+
provider?: string;
|
|
3416
|
+
baseUrl?: string;
|
|
3417
|
+
models?: string[];
|
|
3418
|
+
apiPaths?: Record<string, unknown>;
|
|
3419
|
+
workerEndpoints?: Record<string, Record<string, unknown>>;
|
|
3420
|
+
workerProfiles?: Record<string, Record<string, unknown>>;
|
|
3412
3421
|
candidates: Array<Record<string, unknown>>;
|
|
3413
3422
|
}
|
|
3423
|
+
interface AdaptiveRoutingResolution {
|
|
3424
|
+
status?: string;
|
|
3425
|
+
selected?: Record<string, unknown>;
|
|
3426
|
+
policyDecision?: Record<string, unknown>;
|
|
3427
|
+
evaluatedCount?: number;
|
|
3428
|
+
rejectedCount?: number;
|
|
3429
|
+
fallback?: string;
|
|
3430
|
+
reasons?: string[];
|
|
3431
|
+
warnings?: string[];
|
|
3432
|
+
}
|
|
3414
3433
|
interface AdaptiveWorkRoutingRecommendation {
|
|
3415
3434
|
workProfile: AdaptiveWorkProfile;
|
|
3416
3435
|
requirements: AdaptiveModelRequirements;
|
|
3417
3436
|
routingCard: AdaptiveRoutingCard;
|
|
3418
3437
|
gateway?: AdaptiveRoutingGatewayStatus;
|
|
3419
3438
|
runtimeCatalog?: AdaptiveRoutingRuntimeCatalog;
|
|
3439
|
+
resolution?: AdaptiveRoutingResolution;
|
|
3420
3440
|
}
|
|
3421
3441
|
interface AdaptiveWorkRoutingOptions {
|
|
3422
3442
|
query: string;
|
|
@@ -3426,6 +3446,8 @@ interface AdaptiveWorkRoutingOptions {
|
|
|
3426
3446
|
allowedEndpointTypes?: string[];
|
|
3427
3447
|
workerRole?: string;
|
|
3428
3448
|
plannerRetainsReasoning?: boolean;
|
|
3449
|
+
preferredProfileStrengths?: string[];
|
|
3450
|
+
structuredOutputRequired?: boolean;
|
|
3429
3451
|
catalogLimit?: number;
|
|
3430
3452
|
dailyBudgetCents?: number;
|
|
3431
3453
|
monthlyBudgetCents?: number;
|
|
@@ -3458,6 +3480,7 @@ interface OrchestratorHandoffArtifact {
|
|
|
3458
3480
|
routingCard?: AdaptiveRoutingCard;
|
|
3459
3481
|
gateway?: AdaptiveRoutingGatewayStatus;
|
|
3460
3482
|
runtimeCatalog?: AdaptiveRoutingRuntimeCatalog;
|
|
3483
|
+
resolution?: AdaptiveRoutingResolution;
|
|
3461
3484
|
};
|
|
3462
3485
|
task: {
|
|
3463
3486
|
title: string;
|
package/dist/index.js
CHANGED
|
@@ -14627,7 +14627,8 @@ function buildOrchestratorHandoff(options) {
|
|
|
14627
14627
|
requirements: options.adaptiveRouting.requirements,
|
|
14628
14628
|
routingCard: options.adaptiveRouting.routingCard,
|
|
14629
14629
|
...options.adaptiveRouting.gateway ? { gateway: options.adaptiveRouting.gateway } : {},
|
|
14630
|
-
...options.adaptiveRouting.runtimeCatalog ? { runtimeCatalog: options.adaptiveRouting.runtimeCatalog } : {}
|
|
14630
|
+
...options.adaptiveRouting.runtimeCatalog ? { runtimeCatalog: options.adaptiveRouting.runtimeCatalog } : {},
|
|
14631
|
+
...options.adaptiveRouting.resolution ? { resolution: options.adaptiveRouting.resolution } : {}
|
|
14631
14632
|
} : {}
|
|
14632
14633
|
},
|
|
14633
14634
|
task: {
|
|
@@ -14680,8 +14681,12 @@ function buildAdaptiveWorkRoutingRecommendation(options) {
|
|
|
14680
14681
|
const reasoningDepth = inferAdaptiveReasoningDepth(risk, taskType);
|
|
14681
14682
|
const workerRole = options.workerRole ?? inferAdaptiveWorkerRole(taskType);
|
|
14682
14683
|
const plannerRetainsReasoning = options.plannerRetainsReasoning ?? preferredEndpointTypes.includes("local");
|
|
14684
|
+
const preferredProfileStrengths = normalizeProfileStrengths(
|
|
14685
|
+
options.preferredProfileStrengths ?? inferAdaptivePreferredProfileStrengths(taskType, options.query, changedFiles, workerRole)
|
|
14686
|
+
);
|
|
14683
14687
|
const capabilities = inferAdaptiveCapabilities(taskType, workerRole);
|
|
14684
14688
|
const forbiddenCapabilities = risk === "high" ? ["secrets", "prod_write"] : ["secrets"];
|
|
14689
|
+
const structuredOutputRequired = options.structuredOutputRequired ?? inferAdaptiveStructuredOutputRequirement(taskType, options.query, changedFiles, workerRole);
|
|
14685
14690
|
const workProfile = compactObject2({
|
|
14686
14691
|
taskType,
|
|
14687
14692
|
risk,
|
|
@@ -14689,6 +14694,7 @@ function buildAdaptiveWorkRoutingRecommendation(options) {
|
|
|
14689
14694
|
contextBudget,
|
|
14690
14695
|
reasoningDepth,
|
|
14691
14696
|
evidenceRequirements: inferAdaptiveEvidenceRequirements(options.query, risk),
|
|
14697
|
+
preferredProfileStrengths,
|
|
14692
14698
|
notes: [
|
|
14693
14699
|
"Generated by snipara-companion as recommendation-only routing metadata.",
|
|
14694
14700
|
"snipara-orchestrator must resolve the worker against the runtime catalog before execution."
|
|
@@ -14704,6 +14710,7 @@ function buildAdaptiveWorkRoutingRecommendation(options) {
|
|
|
14704
14710
|
capabilities,
|
|
14705
14711
|
forbiddenCapabilities,
|
|
14706
14712
|
writeScope: changedFiles,
|
|
14713
|
+
structuredOutputRequired: structuredOutputRequired ? true : void 0,
|
|
14707
14714
|
preferredEndpointTypes,
|
|
14708
14715
|
allowedEndpointTypes,
|
|
14709
14716
|
catalogLimit: options.catalogLimit,
|
|
@@ -14820,6 +14827,54 @@ function inferAdaptiveCapabilities(taskType, workerRole) {
|
|
|
14820
14827
|
}
|
|
14821
14828
|
return ["execution"];
|
|
14822
14829
|
}
|
|
14830
|
+
function inferAdaptivePreferredProfileStrengths(taskType, query, changedFiles, workerRole) {
|
|
14831
|
+
const normalizedQuery = query.toLowerCase();
|
|
14832
|
+
const strengths = /* @__PURE__ */ new Set();
|
|
14833
|
+
const codeLikeScope = workerRole === "coding" || workerRole === "testing" || taskType === "coding" || taskType === "critical_code" || changedFiles.some((file) => /\.(ts|tsx|js|jsx|py|go|rs|java|kt|swift|rb|php)$/i.test(file));
|
|
14834
|
+
if (codeLikeScope) {
|
|
14835
|
+
strengths.add("code");
|
|
14836
|
+
}
|
|
14837
|
+
if (/\b(structured|json|schema|signature|serialization|contract|patch|file operations?)\b/i.test(
|
|
14838
|
+
normalizedQuery
|
|
14839
|
+
) || codeLikeScope) {
|
|
14840
|
+
strengths.add("structured_output");
|
|
14841
|
+
}
|
|
14842
|
+
if (/\b(refactor|rewrite|rename|sweep|cross-file|multi-file)\b/i.test(normalizedQuery) || changedFiles.length > 8) {
|
|
14843
|
+
strengths.add("refactor");
|
|
14844
|
+
}
|
|
14845
|
+
if (/\b(repo|repository|codebase|explore|scan|survey|context|continuity|architecture)\b/i.test(
|
|
14846
|
+
normalizedQuery
|
|
14847
|
+
) || changedFiles.length > 5) {
|
|
14848
|
+
strengths.add("long_context");
|
|
14849
|
+
strengths.add("repo_scan");
|
|
14850
|
+
}
|
|
14851
|
+
if (/\b(agent|workflow|checkpoint|handoff|delegate|orchestrat)\b/i.test(normalizedQuery)) {
|
|
14852
|
+
strengths.add("agentic_exploration");
|
|
14853
|
+
}
|
|
14854
|
+
if (taskType === "release" || taskType === "critical_code" || workerRole === "validation") {
|
|
14855
|
+
strengths.add("execution_safe");
|
|
14856
|
+
}
|
|
14857
|
+
return Array.from(strengths).sort();
|
|
14858
|
+
}
|
|
14859
|
+
function inferAdaptiveStructuredOutputRequirement(taskType, query, changedFiles, workerRole) {
|
|
14860
|
+
if (workerRole === "documentation" && taskType === "documentation") {
|
|
14861
|
+
return false;
|
|
14862
|
+
}
|
|
14863
|
+
if (workerRole === "coding" || workerRole === "testing") {
|
|
14864
|
+
return true;
|
|
14865
|
+
}
|
|
14866
|
+
if (taskType === "coding" || taskType === "critical_code" || taskType === "tests") {
|
|
14867
|
+
return true;
|
|
14868
|
+
}
|
|
14869
|
+
if (/\b(structured|json|schema|signature|serialization|contract|patch|file operations?)\b/i.test(
|
|
14870
|
+
query
|
|
14871
|
+
)) {
|
|
14872
|
+
return true;
|
|
14873
|
+
}
|
|
14874
|
+
return changedFiles.some(
|
|
14875
|
+
(file) => /\.(ts|tsx|js|jsx|py|go|rs|java|kt|swift|rb|php)$/i.test(file)
|
|
14876
|
+
);
|
|
14877
|
+
}
|
|
14823
14878
|
function inferAdaptiveEvidenceRequirements(query, risk) {
|
|
14824
14879
|
const evidence = /* @__PURE__ */ new Set();
|
|
14825
14880
|
if (/\b(test|tests|pytest|unit|integration|e2e|smoke|verify|verification)\b/i.test(query)) {
|
|
@@ -14833,6 +14888,13 @@ function inferAdaptiveEvidenceRequirements(query, risk) {
|
|
|
14833
14888
|
}
|
|
14834
14889
|
return Array.from(evidence).sort();
|
|
14835
14890
|
}
|
|
14891
|
+
function normalizeProfileStrengths(values) {
|
|
14892
|
+
return Array.from(
|
|
14893
|
+
new Set(
|
|
14894
|
+
(values ?? []).map((value) => stringValue8(value)?.toLowerCase()).filter((value) => Boolean(value))
|
|
14895
|
+
)
|
|
14896
|
+
).sort();
|
|
14897
|
+
}
|
|
14836
14898
|
function normalizeEndpointTypes(values) {
|
|
14837
14899
|
return Array.from(
|
|
14838
14900
|
new Set(
|
|
@@ -18236,6 +18298,7 @@ var FINAL_COMMIT_RETRY_TIMEOUT_MS = 45e3;
|
|
|
18236
18298
|
var FINAL_COMMIT_SUMMARY_MAX_CHARS = 1200;
|
|
18237
18299
|
var FINAL_COMMIT_RETRY_SUMMARY_MAX_CHARS = 600;
|
|
18238
18300
|
var DEFAULT_ADAPTIVE_ROUTING_CATALOG_LIMIT = 20;
|
|
18301
|
+
var DEFAULT_LOCAL_ORCHESTRATOR_TIMEOUT_MS = 8e3;
|
|
18239
18302
|
var ADAPTIVE_ROUTING_POLICY_RELATIVE_PATH = path21.join(".snipara", "adaptive-routing.json");
|
|
18240
18303
|
var SHARED_CONTEXT_INTENT_PATTERN = /\b(standard|standards|convention|conventions|guideline|guidelines|best practice|best practices|policy|policies|compliance|compliant|security rules|team rules|style guide|playbook|checklist)\b/i;
|
|
18241
18304
|
var DOCUMENT_SYNC_FORMATS = {
|
|
@@ -20777,10 +20840,21 @@ function printAdaptiveRoutingRecommendation(routing) {
|
|
|
20777
20840
|
}
|
|
20778
20841
|
if (routing.gateway) {
|
|
20779
20842
|
printKeyValue(
|
|
20780
|
-
"Hosted catalog:",
|
|
20843
|
+
routing.gateway.source === "local_orchestrator" ? "Local route:" : "Hosted catalog:",
|
|
20781
20844
|
routing.gateway.success ? `${routing.gateway.candidateCount} candidate(s), ${routing.gateway.resolutionStatus ?? "ready"}` : "unavailable"
|
|
20782
20845
|
);
|
|
20783
20846
|
}
|
|
20847
|
+
const selectedCandidate = adaptiveRoutingSelectedCandidate(routing.resolution);
|
|
20848
|
+
if (selectedCandidate) {
|
|
20849
|
+
printKeyValue("Selected candidate:", selectedCandidate.candidateId);
|
|
20850
|
+
if (selectedCandidate.endpointType) {
|
|
20851
|
+
printKeyValue("Selected endpoint:", selectedCandidate.endpointType);
|
|
20852
|
+
}
|
|
20853
|
+
}
|
|
20854
|
+
const selectedWorkerEndpoint = selectedCandidate && routing.runtimeCatalog?.workerEndpoints ? routing.runtimeCatalog.workerEndpoints[selectedCandidate.candidateId] : void 0;
|
|
20855
|
+
if (selectedWorkerEndpoint?.model) {
|
|
20856
|
+
printKeyValue("Selected model:", String(selectedWorkerEndpoint.model));
|
|
20857
|
+
}
|
|
20784
20858
|
if (routing.routingCard.reasons.length > 0) {
|
|
20785
20859
|
console.log("Reasons:");
|
|
20786
20860
|
for (const reason of routing.routingCard.reasons) {
|
|
@@ -20965,11 +21039,191 @@ function normalizeAdaptiveRoutingCatalog(value) {
|
|
|
20965
21039
|
const candidates = Array.isArray(record.candidates) ? record.candidates.filter(
|
|
20966
21040
|
(candidate) => Boolean(candidate) && typeof candidate === "object" && !Array.isArray(candidate)
|
|
20967
21041
|
) : [];
|
|
21042
|
+
const models = Array.isArray(record.models) ? record.models.map((item) => stringValue9(item)).filter((item) => Boolean(item)) : void 0;
|
|
21043
|
+
const workerEndpoints = isRecord12(record.workerEndpoints) ? Object.fromEntries(
|
|
21044
|
+
Object.entries(record.workerEndpoints).filter(
|
|
21045
|
+
([key, value2]) => Boolean(stringValue9(key)) && isRecord12(value2)
|
|
21046
|
+
)
|
|
21047
|
+
) : void 0;
|
|
21048
|
+
const workerProfiles = isRecord12(record.workerProfiles) ? Object.fromEntries(
|
|
21049
|
+
Object.entries(record.workerProfiles).filter(
|
|
21050
|
+
([key, value2]) => Boolean(stringValue9(key)) && isRecord12(value2)
|
|
21051
|
+
)
|
|
21052
|
+
) : void 0;
|
|
20968
21053
|
return {
|
|
20969
21054
|
version: stringValue9(record.version),
|
|
21055
|
+
source: stringValue9(record.source),
|
|
21056
|
+
provider: stringValue9(record.provider),
|
|
21057
|
+
baseUrl: stringValue9(record.baseUrl),
|
|
21058
|
+
...models && models.length > 0 ? { models } : {},
|
|
21059
|
+
...isRecord12(record.apiPaths) ? { apiPaths: record.apiPaths } : {},
|
|
21060
|
+
...workerEndpoints ? { workerEndpoints } : {},
|
|
21061
|
+
...workerProfiles ? { workerProfiles } : {},
|
|
20970
21062
|
candidates
|
|
20971
21063
|
};
|
|
20972
21064
|
}
|
|
21065
|
+
function adaptiveRoutingSelectedCandidate(resolution) {
|
|
21066
|
+
if (!resolution || !isRecord12(resolution.selected)) {
|
|
21067
|
+
return void 0;
|
|
21068
|
+
}
|
|
21069
|
+
const candidate = isRecord12(resolution.selected.candidate) ? resolution.selected.candidate : void 0;
|
|
21070
|
+
const candidateId = stringValue9(candidate?.candidateId);
|
|
21071
|
+
if (!candidateId) {
|
|
21072
|
+
return void 0;
|
|
21073
|
+
}
|
|
21074
|
+
return {
|
|
21075
|
+
candidateId,
|
|
21076
|
+
workerClass: stringValue9(candidate?.workerClass),
|
|
21077
|
+
endpointType: stringValue9(candidate?.endpointType),
|
|
21078
|
+
catalogSource: stringValue9(candidate?.catalogSource)
|
|
21079
|
+
};
|
|
21080
|
+
}
|
|
21081
|
+
function normalizeAdaptiveRoutingResolution(value) {
|
|
21082
|
+
if (!isRecord12(value)) {
|
|
21083
|
+
return void 0;
|
|
21084
|
+
}
|
|
21085
|
+
const selected = isRecord12(value.selected) ? value.selected : void 0;
|
|
21086
|
+
const candidate = selected && isRecord12(selected.candidate) ? selected.candidate : void 0;
|
|
21087
|
+
const selectedPayload = selected && candidate ? {
|
|
21088
|
+
candidate,
|
|
21089
|
+
...numberValue6(selected.score) !== void 0 ? { score: numberValue6(selected.score) } : {},
|
|
21090
|
+
...isRecord12(selected.scoreBreakdown) ? { scoreBreakdown: selected.scoreBreakdown } : {},
|
|
21091
|
+
...normalizeStringArray3(selected.reasons) ? { reasons: normalizeStringArray3(selected.reasons) } : {}
|
|
21092
|
+
} : void 0;
|
|
21093
|
+
const reasons = normalizeStringArray3(value.reasons);
|
|
21094
|
+
const warnings = normalizeStringArray3(value.warnings);
|
|
21095
|
+
return {
|
|
21096
|
+
status: stringValue9(value.status),
|
|
21097
|
+
...selectedPayload ? { selected: selectedPayload } : {},
|
|
21098
|
+
...isRecord12(value.policyDecision) ? { policyDecision: value.policyDecision } : {},
|
|
21099
|
+
...numberValue6(value.evaluatedCount) !== void 0 ? { evaluatedCount: numberValue6(value.evaluatedCount) } : {},
|
|
21100
|
+
...numberValue6(value.rejectedCount) !== void 0 ? { rejectedCount: numberValue6(value.rejectedCount) } : {},
|
|
21101
|
+
...stringValue9(value.fallback) ? { fallback: stringValue9(value.fallback) } : {},
|
|
21102
|
+
...reasons ? { reasons } : {},
|
|
21103
|
+
...warnings ? { warnings } : {}
|
|
21104
|
+
};
|
|
21105
|
+
}
|
|
21106
|
+
function shouldResolveAdaptiveRoutingLocally(options, routing) {
|
|
21107
|
+
if (!routing) {
|
|
21108
|
+
return false;
|
|
21109
|
+
}
|
|
21110
|
+
if (!options.routeLocalWorkers && !options.routingLocalBaseUrl && !options.routingLocalModel && !options.routingLocalPreferModel && !options.routingLocalProvider) {
|
|
21111
|
+
return false;
|
|
21112
|
+
}
|
|
21113
|
+
const preferred = routing.requirements.preferredEndpointTypes ?? [];
|
|
21114
|
+
const allowed = routing.requirements.allowedEndpointTypes ?? [];
|
|
21115
|
+
return preferred.includes("local") || allowed.length === 0 || allowed.includes("local");
|
|
21116
|
+
}
|
|
21117
|
+
function runOrchestratorJsonCommand(args, cwd = process.cwd()) {
|
|
21118
|
+
const output = (0, import_node_child_process8.execFileSync)("snipara-orchestrator", args, {
|
|
21119
|
+
cwd,
|
|
21120
|
+
encoding: "utf8",
|
|
21121
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
21122
|
+
timeout: DEFAULT_LOCAL_ORCHESTRATOR_TIMEOUT_MS
|
|
21123
|
+
}).trim();
|
|
21124
|
+
return output ? parseJsonRecord(output, "snipara-orchestrator JSON output") : {};
|
|
21125
|
+
}
|
|
21126
|
+
function enrichAdaptiveRoutingWithLocalOrchestrator(routing, options, cwd = process.cwd()) {
|
|
21127
|
+
try {
|
|
21128
|
+
const catalogArgs = [
|
|
21129
|
+
"local-model-catalog",
|
|
21130
|
+
"--json",
|
|
21131
|
+
"--worker-role",
|
|
21132
|
+
routing.requirements.workerRole
|
|
21133
|
+
];
|
|
21134
|
+
for (const writeScope of routing.requirements.writeScope ?? []) {
|
|
21135
|
+
catalogArgs.push("--write-scope", writeScope);
|
|
21136
|
+
}
|
|
21137
|
+
if (options.routingLocalBaseUrl) {
|
|
21138
|
+
catalogArgs.push("--base-url", options.routingLocalBaseUrl);
|
|
21139
|
+
}
|
|
21140
|
+
if (options.routingLocalModel) {
|
|
21141
|
+
catalogArgs.push("--model", options.routingLocalModel);
|
|
21142
|
+
} else if (options.routingLocalPreferModel) {
|
|
21143
|
+
catalogArgs.push("--prefer-model", options.routingLocalPreferModel);
|
|
21144
|
+
} else if (options.routeLocalWorkers) {
|
|
21145
|
+
catalogArgs.push("--all-models");
|
|
21146
|
+
}
|
|
21147
|
+
if (options.routingLocalProvider) {
|
|
21148
|
+
catalogArgs.push("--provider", options.routingLocalProvider);
|
|
21149
|
+
}
|
|
21150
|
+
const runtimeCatalog = normalizeAdaptiveRoutingCatalog(
|
|
21151
|
+
runOrchestratorJsonCommand(catalogArgs, cwd)
|
|
21152
|
+
);
|
|
21153
|
+
const routeArgs = [
|
|
21154
|
+
"route",
|
|
21155
|
+
"--dry-run",
|
|
21156
|
+
"--json",
|
|
21157
|
+
"--work-profile-json",
|
|
21158
|
+
JSON.stringify(routing.workProfile),
|
|
21159
|
+
"--requirements-json",
|
|
21160
|
+
JSON.stringify(routing.requirements)
|
|
21161
|
+
];
|
|
21162
|
+
for (const candidate of runtimeCatalog.candidates) {
|
|
21163
|
+
routeArgs.push("--candidate-json", JSON.stringify(candidate));
|
|
21164
|
+
}
|
|
21165
|
+
const resolution = normalizeAdaptiveRoutingResolution(
|
|
21166
|
+
runOrchestratorJsonCommand(routeArgs, cwd)
|
|
21167
|
+
);
|
|
21168
|
+
const selectedCandidate = adaptiveRoutingSelectedCandidate(resolution);
|
|
21169
|
+
const selectedEndpoint = selectedCandidate && runtimeCatalog.workerEndpoints ? runtimeCatalog.workerEndpoints[selectedCandidate.candidateId] : void 0;
|
|
21170
|
+
const resolutionWarnings = normalizeStringArray3(resolution?.warnings) ?? [];
|
|
21171
|
+
const resolutionReasons = normalizeStringArray3(resolution?.reasons) ?? [];
|
|
21172
|
+
const approvalRequired = booleanValue2(
|
|
21173
|
+
isRecord12(resolution?.policyDecision) ? resolution.policyDecision.approvalRequired : void 0
|
|
21174
|
+
);
|
|
21175
|
+
const gatewayWarnings = uniqueStrings5([
|
|
21176
|
+
...resolutionWarnings,
|
|
21177
|
+
...selectedCandidate ? [] : ["Local orchestrator did not select a worker candidate and will fail closed."]
|
|
21178
|
+
]);
|
|
21179
|
+
const gateway = {
|
|
21180
|
+
source: "local_orchestrator",
|
|
21181
|
+
success: stringValue9(resolution?.status) === "resolved",
|
|
21182
|
+
resolutionStatus: stringValue9(resolution?.status),
|
|
21183
|
+
candidateCount: runtimeCatalog.candidates.length,
|
|
21184
|
+
fallback: stringValue9(resolution?.fallback) ?? routing.requirements.fallback,
|
|
21185
|
+
warnings: gatewayWarnings
|
|
21186
|
+
};
|
|
21187
|
+
return {
|
|
21188
|
+
...routing,
|
|
21189
|
+
gateway,
|
|
21190
|
+
runtimeCatalog,
|
|
21191
|
+
...resolution ? { resolution } : {},
|
|
21192
|
+
routingCard: {
|
|
21193
|
+
...routing.routingCard,
|
|
21194
|
+
...selectedCandidate?.workerClass ? { recommendedWorkerClass: selectedCandidate.workerClass } : {},
|
|
21195
|
+
...approvalRequired !== void 0 ? { humanApprovalRequired: approvalRequired } : {},
|
|
21196
|
+
reasons: uniqueStrings5([
|
|
21197
|
+
...routing.routingCard.reasons,
|
|
21198
|
+
...resolutionReasons,
|
|
21199
|
+
...selectedCandidate ? [
|
|
21200
|
+
`local orchestrator resolved worker candidate ${selectedCandidate.candidateId}`,
|
|
21201
|
+
...selectedCandidate.endpointType ? [`selected worker endpoint is ${selectedCandidate.endpointType}`] : [],
|
|
21202
|
+
...stringValue9(selectedEndpoint?.model) ? [`selected local model ${String(selectedEndpoint?.model)}`] : []
|
|
21203
|
+
] : ["local orchestrator could not resolve a concrete worker candidate"]
|
|
21204
|
+
]),
|
|
21205
|
+
warnings: uniqueStrings5([...routing.routingCard.warnings, ...gatewayWarnings])
|
|
21206
|
+
}
|
|
21207
|
+
};
|
|
21208
|
+
} catch (error) {
|
|
21209
|
+
const warning = `Local orchestrator routing unavailable; keeping current routing metadata (${toPreview(error)}).`;
|
|
21210
|
+
return {
|
|
21211
|
+
...routing,
|
|
21212
|
+
gateway: {
|
|
21213
|
+
source: "local_orchestrator",
|
|
21214
|
+
success: false,
|
|
21215
|
+
resolutionStatus: "unavailable",
|
|
21216
|
+
candidateCount: 0,
|
|
21217
|
+
fallback: routing.requirements.fallback,
|
|
21218
|
+
warnings: [warning]
|
|
21219
|
+
},
|
|
21220
|
+
routingCard: {
|
|
21221
|
+
...routing.routingCard,
|
|
21222
|
+
warnings: uniqueStrings5([...routing.routingCard.warnings, warning])
|
|
21223
|
+
}
|
|
21224
|
+
};
|
|
21225
|
+
}
|
|
21226
|
+
}
|
|
20973
21227
|
function printUploadResult(path23, result) {
|
|
20974
21228
|
printKeyValue("Uploaded:", path23);
|
|
20975
21229
|
printCompactObject(result, ["message", "document_id", "documentId", "version", "status"]);
|
|
@@ -22456,7 +22710,8 @@ async function workflowRunCommand(options) {
|
|
|
22456
22710
|
hostedConfigured
|
|
22457
22711
|
);
|
|
22458
22712
|
const adaptiveRoutingDryRun = adaptiveRoutingIntent.shouldBuild ? buildWorkflowAdaptiveRouting(options, adaptiveRoutingPolicy, adaptiveRoutingIntent.warnings) : null;
|
|
22459
|
-
const
|
|
22713
|
+
const adaptiveRoutingWithCatalog = adaptiveRoutingDryRun && adaptiveRoutingIntent.shouldUseHostedCatalog && client ? await enrichAdaptiveRoutingWithHostedCatalog(client, adaptiveRoutingDryRun) : adaptiveRoutingDryRun;
|
|
22714
|
+
const adaptiveRouting = shouldResolveAdaptiveRoutingLocally(options, adaptiveRoutingWithCatalog) ? enrichAdaptiveRoutingWithLocalOrchestrator(adaptiveRoutingWithCatalog, options) : adaptiveRoutingWithCatalog;
|
|
22460
22715
|
const orchestratorRecommendation = getOrchestratorRecommendation(options.query, options.mode, {
|
|
22461
22716
|
policyAutoRoute: options.autoRouteOrchestrator,
|
|
22462
22717
|
policySource: options.orchestratorPolicySource,
|
|
@@ -22679,7 +22934,7 @@ async function workflowRunCommand(options) {
|
|
|
22679
22934
|
}
|
|
22680
22935
|
function shouldBuildAdaptiveRouting(options) {
|
|
22681
22936
|
return Boolean(
|
|
22682
|
-
options.adaptiveRoutingDryRun || options.routeLocalWorkers || options.routingWorkerRole || options.routingPreferredEndpoints?.length || options.routingAllowedEndpoints?.length || options.plannerRetainsReasoning
|
|
22937
|
+
options.adaptiveRoutingDryRun || options.routeLocalWorkers || options.routingWorkerRole || options.routingPreferredEndpoints?.length || options.routingAllowedEndpoints?.length || options.routingLocalBaseUrl || options.routingLocalModel || options.routingLocalPreferModel || options.routingLocalProvider || options.plannerRetainsReasoning
|
|
22683
22938
|
);
|
|
22684
22939
|
}
|
|
22685
22940
|
function buildWorkflowAdaptiveRouting(options, policy = null, intentWarnings = []) {
|
|
@@ -24794,6 +25049,12 @@ workflow.command("run").description("Run a LITE/STANDARD/FULL/orchestrate workfl
|
|
|
24794
25049
|
collectOption,
|
|
24795
25050
|
[]
|
|
24796
25051
|
).option(
|
|
25052
|
+
"--routing-local-base-url <url>",
|
|
25053
|
+
"Local OpenAI-compatible runtime base URL for explicit worker routing"
|
|
25054
|
+
).option("--routing-local-model <id>", "Explicit local model id for worker routing").option(
|
|
25055
|
+
"--routing-local-prefer-model <text>",
|
|
25056
|
+
"Prefer a local /v1/models entry containing this text during worker routing"
|
|
25057
|
+
).option("--routing-local-provider <provider>", "Provider label for local worker routing").option(
|
|
24797
25058
|
"--planner-retains-reasoning",
|
|
24798
25059
|
"Mark the main planner as retaining deep reasoning while the worker executes scoped work"
|
|
24799
25060
|
).option("--write-plan-file <file>", "Write the generated FULL-mode plan as workflow JSON").option(
|
|
@@ -24816,6 +25077,10 @@ workflow.command("run").description("Run a LITE/STANDARD/FULL/orchestrate workfl
|
|
|
24816
25077
|
routingWorkerRole: options.routingWorkerRole,
|
|
24817
25078
|
routingPreferredEndpoints: options.routingPreferredEndpoint,
|
|
24818
25079
|
routingAllowedEndpoints: options.routingAllowedEndpoint,
|
|
25080
|
+
routingLocalBaseUrl: options.routingLocalBaseUrl,
|
|
25081
|
+
routingLocalModel: options.routingLocalModel,
|
|
25082
|
+
routingLocalPreferModel: options.routingLocalPreferModel,
|
|
25083
|
+
routingLocalProvider: options.routingLocalProvider,
|
|
24819
25084
|
plannerRetainsReasoning: options.plannerRetainsReasoning ? true : void 0,
|
|
24820
25085
|
writePlanFile: options.writePlanFile,
|
|
24821
25086
|
startWorkflowFromPlan: Boolean(options.startWorkflowFromPlan),
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -273,6 +273,62 @@ Project credentials stay server-side behind the hosted gateway; local endpoints
|
|
|
273
273
|
such as Ollama, LM Studio, AnythingLLM, or other OpenAI-compatible servers must
|
|
274
274
|
be reachable from the worker execution environment.
|
|
275
275
|
|
|
276
|
+
For a local LM Studio or OpenAI-compatible worker, use Companion to emit the
|
|
277
|
+
handoff, then let `snipara-orchestrator` resolve that handoff against an explicit
|
|
278
|
+
local runtime catalog. In the Codex workflow, Codex remains the chief architect,
|
|
279
|
+
lead orchestrator, and quality verifier; Qwen and Devstral are bounded local
|
|
280
|
+
worker candidates whose outputs still need Codex review and proof gates.
|
|
281
|
+
|
|
282
|
+
Use Qwen for reflection, architecture, and documentation:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
snipara-companion workflow run \
|
|
286
|
+
--mode full \
|
|
287
|
+
--adaptive-routing-dry-run \
|
|
288
|
+
--route-local-workers \
|
|
289
|
+
--routing-worker-role documentation \
|
|
290
|
+
--routing-preferred-endpoint local \
|
|
291
|
+
--routing-allowed-endpoint local \
|
|
292
|
+
--planner-retains-reasoning \
|
|
293
|
+
"Update a scoped docs surface"
|
|
294
|
+
|
|
295
|
+
snipara-orchestrator local-model-catalog \
|
|
296
|
+
--base-url http://127.0.0.1:1234 \
|
|
297
|
+
--model qwen/qwen3-30b-a3b-2507 \
|
|
298
|
+
--worker-role documentation \
|
|
299
|
+
--capability documentation \
|
|
300
|
+
--capability architecture_review \
|
|
301
|
+
--capability planning \
|
|
302
|
+
--json > .snipara/local-qwen-docs-runtime-catalog.json
|
|
303
|
+
|
|
304
|
+
snipara-orchestrator route --dry-run \
|
|
305
|
+
--work-profile-json '{"taskType":"documentation","risk":"low","scope":["docs/**"],"contextBudget":"small","reasoningDepth":"low"}' \
|
|
306
|
+
--requirements-json '{"workerRole":"documentation","plannerRetainsReasoning":true,"preferredEndpointTypes":["local"],"allowedEndpointTypes":["local"],"writeScope":["docs/**"],"capabilities":["documentation"]}' \
|
|
307
|
+
--catalog-file .snipara/local-qwen-docs-runtime-catalog.json \
|
|
308
|
+
--json
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Use Devstral for development and refactoring work:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
snipara-orchestrator local-model-catalog \
|
|
315
|
+
--base-url http://127.0.0.1:1234 \
|
|
316
|
+
--prefer-model devstral \
|
|
317
|
+
--worker-role coding \
|
|
318
|
+
--capability code_edit \
|
|
319
|
+
--capability refactor \
|
|
320
|
+
--json > .snipara/local-devstral-runtime-catalog.json
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
The local catalog records the OpenAI-compatible routes exposed by LM Studio:
|
|
324
|
+
`GET /v1/models`, `POST /v1/responses`, `POST /v1/chat/completions`,
|
|
325
|
+
`POST /v1/completions`, and `POST /v1/embeddings`. `--prefer-model devstral`
|
|
326
|
+
selects the first `/v1/models` id containing `devstral`; use `--model <id>` to
|
|
327
|
+
pin Qwen or any other exact local model id. This makes Qwen, Devstral, or
|
|
328
|
+
another local model routable through the Companion/Orchestrator contract while
|
|
329
|
+
keeping execution fail-closed: the selected candidate is a receipt-backed worker
|
|
330
|
+
target, not an automatically launched process.
|
|
331
|
+
|
|
276
332
|
For the open package without Snipara SaaS, add a local policy file:
|
|
277
333
|
|
|
278
334
|
```json
|