orizu 0.5.19 → 0.5.20
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 +23 -0
- package/dist/diff-comments-cli.js +18 -2
- package/dist/gepa-engine-dispatch.js +261 -0
- package/dist/gepa-python-command.js +26 -0
- package/dist/gepa-python-paths.js +39 -0
- package/dist/help.js +4 -4
- package/dist/index.js +34 -40
- package/dist/markdown-report-input.js +15 -1
- package/dist/prompt-length-wire.js +2 -2
- package/dist/prompt-report-cli.js +2 -2
- package/dist/report-markdown-blankness.js +6 -0
- package/dist/report-replacement-warning.js +31 -0
- package/package.json +2 -2
- package/scripts/build-cli-dist.mjs +30 -0
- package/scripts/orizu-source-checkout.d.mts +1 -0
- package/scripts/orizu-source-checkout.mjs +10 -0
- package/scripts/vendor-gepa-python.mjs +187 -4
- package/src/diff-comments-cli.ts +37 -3
- package/src/gepa-engine-dispatch.ts +300 -0
- package/src/gepa-python-command.ts +31 -0
- package/src/gepa-python-paths.ts +53 -0
- package/src/help.ts +4 -4
- package/src/index.ts +35 -43
- package/src/markdown-report-input.ts +19 -1
- package/src/prompt-length-wire.ts +1 -1
- package/src/prompt-report-cli.ts +2 -2
- package/src/report-markdown-blankness.ts +6 -0
- package/src/report-replacement-warning.ts +35 -0
- package/vendor/gepa-python/LICENSE +7 -0
- package/vendor/gepa-python/manifest.json +107 -0
- package/vendor/gepa-python/src/gepa/__init__.py +22 -0
- package/vendor/gepa-python/src/gepa/adapters/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/__init__.py +1 -0
- package/vendor/gepa-python/src/gepa/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
- package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/__init__.py +26 -0
- package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/confidence_adapter.py +618 -0
- package/vendor/gepa-python/src/gepa/adapters/confidence_adapter/scoring.py +206 -0
- package/vendor/gepa-python/src/gepa/adapters/default_adapter/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/default_adapter/default_adapter.py +206 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/dspy_adapter.py +525 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_adapter/instruction_proposal.py +500 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/__init__.py +6 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
- package/vendor/gepa-python/src/gepa/adapters/dspy_full_program_adapter/full_program_adapter.py +269 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/__init__.py +56 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
- package/vendor/gepa-python/src/gepa/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
- package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/__init__.py +11 -0
- package/vendor/gepa-python/src/gepa/adapters/langchain_adapter/langchain_adapter.py +261 -0
- package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/__init__.py +37 -0
- package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_adapter.py +693 -0
- package/vendor/gepa-python/src/gepa/adapters/mcp_adapter/mcp_client.py +364 -0
- package/vendor/gepa-python/src/gepa/adapters/optimize_anything_adapter/optimize_anything_adapter.py +879 -0
- package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
- package/vendor/gepa-python/src/gepa/api.py +468 -0
- package/vendor/gepa-python/src/gepa/core/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/core/adapter.py +227 -0
- package/vendor/gepa-python/src/gepa/core/callbacks.py +551 -0
- package/vendor/gepa-python/src/gepa/core/data_loader.py +74 -0
- package/vendor/gepa-python/src/gepa/core/engine.py +1025 -0
- package/vendor/gepa-python/src/gepa/core/result.py +271 -0
- package/vendor/gepa-python/src/gepa/core/state.py +706 -0
- package/vendor/gepa-python/src/gepa/examples/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/examples/aime.py +24 -0
- package/vendor/gepa-python/src/gepa/examples/anymaths-bench/eval_default.py +111 -0
- package/vendor/gepa-python/src/gepa/examples/anymaths-bench/train_anymaths.py +177 -0
- package/vendor/gepa-python/src/gepa/examples/mcp_adapter/__init__.py +4 -0
- package/vendor/gepa-python/src/gepa/examples/mcp_adapter/mcp_optimization_example.py +456 -0
- package/vendor/gepa-python/src/gepa/examples/rag_adapter/__init__.py +9 -0
- package/vendor/gepa-python/src/gepa/examples/rag_adapter/rag_optimization.py +824 -0
- package/vendor/gepa-python/src/gepa/examples/terminal-bench/train_terminus.py +161 -0
- package/vendor/gepa-python/src/gepa/gepa_utils.py +117 -0
- package/vendor/gepa-python/src/gepa/gskill/__init__.py +1 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/cost_tracker.py +194 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code.py +1117 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/claude_code_skills.py +613 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/evaluate/mini_swe_agent.py +440 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/experiment_logger.py +367 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/swe_fitness_fn.py +209 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/swe_harness.py +352 -0
- package/vendor/gepa-python/src/gepa/gskill/gskill/train_optimize_anything.py +830 -0
- package/vendor/gepa-python/src/gepa/image.py +104 -0
- package/vendor/gepa-python/src/gepa/lm.py +261 -0
- package/vendor/gepa-python/src/gepa/logging/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/logging/experiment_tracker.py +457 -0
- package/vendor/gepa-python/src/gepa/logging/logger.py +75 -0
- package/vendor/gepa-python/src/gepa/logging/utils.py +130 -0
- package/vendor/gepa-python/src/gepa/optimize_anything.py +1701 -0
- package/vendor/gepa-python/src/gepa/proposer/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/proposer/base.py +53 -0
- package/vendor/gepa-python/src/gepa/proposer/merge.py +403 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/base.py +64 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflection_lm.py +178 -0
- package/vendor/gepa-python/src/gepa/proposer/reflective_mutation/reflective_mutation.py +641 -0
- package/vendor/gepa-python/src/gepa/py.typed +0 -0
- package/vendor/gepa-python/src/gepa/strategies/__init__.py +0 -0
- package/vendor/gepa-python/src/gepa/strategies/acceptance.py +66 -0
- package/vendor/gepa-python/src/gepa/strategies/batch_sampler.py +103 -0
- package/vendor/gepa-python/src/gepa/strategies/candidate_selector.py +82 -0
- package/vendor/gepa-python/src/gepa/strategies/component_selector.py +36 -0
- package/vendor/gepa-python/src/gepa/strategies/eval_policy.py +64 -0
- package/vendor/gepa-python/src/gepa/strategies/instruction_proposal.py +153 -0
- package/vendor/gepa-python/src/gepa/strategies/proposal_sampling.py +128 -0
- package/vendor/gepa-python/src/gepa/strategies/proposal_selection.py +84 -0
- package/vendor/gepa-python/src/gepa/utils/__init__.py +63 -0
- package/vendor/gepa-python/src/gepa/utils/code_execution.py +626 -0
- package/vendor/gepa-python/src/gepa/utils/stdio_capture.py +145 -0
- package/vendor/gepa-python/src/gepa/utils/stop_condition.py +230 -0
- package/vendor/gepa-python/src/gepa/visualization.py +359 -0
- package/vendor/orizu-gepa/pyproject.toml +18 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/__init__.py +8 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/__main__.py +5 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/adapter.py +132 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/callbacks.py +652 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/cli.py +7 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +177 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/preflight.py +64 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/reflection.py +106 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +643 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/stop_conditions.py +38 -0
- package/vendor/orizu-gepa/src/orizu_gepa_connector/translator.py +202 -0
- package/vendor/orizu-gepa-python/pyproject.toml +1 -1
- package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/local_log.py +49 -0
- package/vendor/skills/orizu-cli/SKILL.md +1 -1
- package/vendor/skills/orizu-cli/references/optimization-reports.md +1 -1
- package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +1 -1
- package/vendor/skills/orizu-cli/references/prompt-control-plane.md +6 -3
package/README.md
CHANGED
|
@@ -25,6 +25,29 @@ Note: the one task we do _not_ let you perform from your CLI is any reviews assi
|
|
|
25
25
|
|
|
26
26
|
By default, the CLI talks to `https://orizu.ai`.
|
|
27
27
|
|
|
28
|
+
## Updating bundled GEPA
|
|
29
|
+
|
|
30
|
+
The CLI ships a verified, source-only copy of official GEPA so optimization
|
|
31
|
+
users never need `pip` or a network connection. To upgrade it, make a PR that
|
|
32
|
+
updates the version, release commit, and SHA-256 pin in
|
|
33
|
+
`scripts/vendor-gepa-python.mjs`, then re-runs the refresh command with the
|
|
34
|
+
matching downloaded wheel:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node scripts/vendor-gepa-python.mjs --refresh --archive /path/to/gepa-<version>-py3-none-any.whl
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Commit the refreshed `gepa-python-source.zip` and run the CLI packaging test.
|
|
41
|
+
`npm pack` verifies that archive and materializes only the shipped source tree;
|
|
42
|
+
it never downloads GEPA.
|
|
43
|
+
|
|
44
|
+
For a development checkout, materialize that same verified source before local
|
|
45
|
+
work that imports GEPA:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node scripts/vendor-gepa-python.mjs
|
|
49
|
+
```
|
|
50
|
+
|
|
28
51
|
## Install
|
|
29
52
|
|
|
30
53
|
Install the CLI globally with your package manager:
|
|
@@ -61,6 +61,16 @@ function formatDeltaValue(value, metric, signed = false) {
|
|
|
61
61
|
return '—';
|
|
62
62
|
return metric === 'tokens' ? `~${formatted}` : formatted;
|
|
63
63
|
}
|
|
64
|
+
function isLengthMetricDelta(value) {
|
|
65
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const delta = value;
|
|
69
|
+
const isNullableFiniteNumber = (candidate) => candidate === null || (typeof candidate === 'number' && Number.isFinite(candidate));
|
|
70
|
+
return isNullableFiniteNumber(delta.removed) &&
|
|
71
|
+
isNullableFiniteNumber(delta.added) &&
|
|
72
|
+
isNullableFiniteNumber(delta.net);
|
|
73
|
+
}
|
|
64
74
|
function printLengthMeasurements(ctx, pair) {
|
|
65
75
|
function unavailableSuffix(reason) {
|
|
66
76
|
if (typeof reason !== 'string' || reason.length === 0)
|
|
@@ -83,8 +93,10 @@ function printLengthMeasurements(ctx, pair) {
|
|
|
83
93
|
ctx.printLine(` Length delta: unavailable${unavailableSuffix(pair.lengthDeltaUnavailableReason ?? pair.degraded?.reason)}`);
|
|
84
94
|
return;
|
|
85
95
|
}
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
const splitUnavailableReason = pair.lengthDelta.splitUnavailableReason;
|
|
97
|
+
if (typeof splitUnavailableReason === 'string' &&
|
|
98
|
+
splitUnavailableReason.length > 0) {
|
|
99
|
+
ctx.printLine(` Split unavailable: ${sanitizeHumanInlineText(ctx.sanitizeTerminalText, splitUnavailableReason)}`);
|
|
88
100
|
}
|
|
89
101
|
for (const [metric, label] of [
|
|
90
102
|
['tokens', 'Tokens'],
|
|
@@ -93,6 +105,10 @@ function printLengthMeasurements(ctx, pair) {
|
|
|
93
105
|
['words', 'Words'],
|
|
94
106
|
]) {
|
|
95
107
|
const delta = pair.lengthDelta[metric];
|
|
108
|
+
if (!isLengthMetricDelta(delta)) {
|
|
109
|
+
ctx.printLine(` ${label}: unavailable`);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
96
112
|
ctx.printLine(` ${label}: removed ${formatDeltaValue(delta.removed, metric)} · ` +
|
|
97
113
|
`added ${formatDeltaValue(delta.added, metric)} · ` +
|
|
98
114
|
`net ${formatDeltaValue(delta.net, metric, true)}`);
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
const VALUE_OPTIONS = [
|
|
3
|
+
{ flag: '--optimizer-version-id', environment: 'ORIZU_OPTIMIZER_VERSION_ID' },
|
|
4
|
+
{ flag: '--candidate-version-id', environment: 'ORIZU_PROMPT_VERSION_ID' },
|
|
5
|
+
{ flag: '--runner-version-id', environment: 'ORIZU_RUNNER_VERSION_ID' },
|
|
6
|
+
{ flag: '--candidate-runner-dir', environment: 'ORIZU_CANDIDATE_RUNNER_DIR' },
|
|
7
|
+
{ flag: '--scorer-version-id', environment: 'ORIZU_SCORER_VERSION_ID' },
|
|
8
|
+
{ flag: '--scorer-runner-version-id', environment: 'ORIZU_SCORER_RUNNER_VERSION_ID' },
|
|
9
|
+
{ flag: '--scorer-runner-dir', environment: 'ORIZU_SCORER_RUNNER_DIR' },
|
|
10
|
+
{ flag: '--scorer-input-contract', environment: 'ORIZU_SCORER_INPUT_CONTRACT' },
|
|
11
|
+
{ flag: '--scorer-candidate-field', environment: 'ORIZU_SCORER_CANDIDATE_FIELD' },
|
|
12
|
+
{ flag: '--dataset-version-id', environment: 'ORIZU_DATASET_VERSION_ID' },
|
|
13
|
+
{ flag: '--split-set-id', environment: 'ORIZU_SPLIT_SET_ID' },
|
|
14
|
+
{ flag: '--train-split', environment: 'ORIZU_TRAIN_SPLIT', allowEmpty: true },
|
|
15
|
+
{ flag: '--val-split', environment: 'ORIZU_VALIDATION_SPLIT', allowEmpty: true },
|
|
16
|
+
{ flag: '--budget', environment: 'ORIZU_BUDGET' },
|
|
17
|
+
{ flag: '--max-iterations', environment: 'ORIZU_MAX_ITERATIONS' },
|
|
18
|
+
{ flag: '--max-candidate-proposals', environment: 'ORIZU_MAX_CANDIDATE_PROPOSALS' },
|
|
19
|
+
{ flag: '--max-full-evals', environment: 'ORIZU_MAX_FULL_EVALS' },
|
|
20
|
+
{ flag: '--max-metric-calls', environment: 'ORIZU_MAX_METRIC_CALLS' },
|
|
21
|
+
{ flag: '--minibatch-size', environment: 'ORIZU_MINIBATCH_SIZE' },
|
|
22
|
+
{ flag: '--num-threads', environment: 'ORIZU_NUM_THREADS' },
|
|
23
|
+
{ flag: '--candidate-selection-strategy', environment: 'ORIZU_CANDIDATE_SELECTION_STRATEGY' },
|
|
24
|
+
{ flag: '--epsilon', environment: 'ORIZU_EPSILON' },
|
|
25
|
+
{ flag: '--reflection-model', environment: 'ORIZU_REFLECTION_MODEL' },
|
|
26
|
+
{ flag: '--reflection-temperature', environment: 'ORIZU_REFLECTION_TEMPERATURE' },
|
|
27
|
+
{ flag: '--reflection-max-tokens', environment: 'ORIZU_REFLECTION_MAX_TOKENS' },
|
|
28
|
+
{ flag: '--reflection-retry-attempts', environment: 'ORIZU_REFLECTION_RETRY_ATTEMPTS' },
|
|
29
|
+
{ flag: '--reflection-http-timeout-seconds', environment: 'ORIZU_REFLECTION_HTTP_TIMEOUT_SECONDS' },
|
|
30
|
+
{ flag: '--reflection-prompt-template', environment: 'ORIZU_REFLECTION_PROMPT_TEMPLATE', readFile: true },
|
|
31
|
+
{ flag: '--reflection-provider-settings', environment: 'ORIZU_REFLECTION_PROVIDER_SETTINGS', readFile: true, json: true },
|
|
32
|
+
{ flag: '--objective', environment: 'ORIZU_OBJECTIVE', allowEmpty: true },
|
|
33
|
+
{ flag: '--seed', environment: 'ORIZU_SEED' },
|
|
34
|
+
{ flag: '--promotion-label', environment: 'ORIZU_PROMOTION_LABEL', allowEmpty: true },
|
|
35
|
+
{ flag: '--log-dir', environment: 'ORIZU_LOCAL_LOG_DIR' },
|
|
36
|
+
];
|
|
37
|
+
const BOOLEAN_OPTIONS = [
|
|
38
|
+
['--allow-degenerate-seed', 'ORIZU_ALLOW_DEGENERATE_SEED', '1'],
|
|
39
|
+
['--disable-evaluation-cache', 'ORIZU_DISABLE_EVALUATION_CACHE', '1'],
|
|
40
|
+
['--auto-promote', 'ORIZU_AUTO_PROMOTE', '1'],
|
|
41
|
+
['--log-row-snapshots', 'ORIZU_LOG_ROW_SNAPSHOTS', '1'],
|
|
42
|
+
['--no-local-log', 'ORIZU_NO_LOCAL_LOG', '1'],
|
|
43
|
+
['--skip-perfect-parent-reflection', 'ORIZU_SKIP_PERFECT_PARENT_REFLECTION', '1'],
|
|
44
|
+
['--no-skip-perfect-parent-reflection', 'ORIZU_SKIP_PERFECT_PARENT_REFLECTION', '0'],
|
|
45
|
+
];
|
|
46
|
+
function textValue(value) {
|
|
47
|
+
if (value.startsWith('@'))
|
|
48
|
+
return readFileSync(value.slice(1), 'utf8');
|
|
49
|
+
const path = value;
|
|
50
|
+
return existsSync(path) ? readFileSync(path, 'utf8') : value;
|
|
51
|
+
}
|
|
52
|
+
function jsonObjectValue(value, flag) {
|
|
53
|
+
const raw = textValue(value);
|
|
54
|
+
const parsed = JSON.parse(raw);
|
|
55
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
56
|
+
throw new Error(`${flag} must be a JSON object`);
|
|
57
|
+
}
|
|
58
|
+
// Validate in JavaScript, but preserve the raw spelling for Python's JSON
|
|
59
|
+
// parser so large numbers and exponent forms do not lose precision here.
|
|
60
|
+
return raw;
|
|
61
|
+
}
|
|
62
|
+
function removeEngine(args) {
|
|
63
|
+
let engine;
|
|
64
|
+
const forwarded = [];
|
|
65
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
66
|
+
const argument = args[index];
|
|
67
|
+
if (argument === '--engine') {
|
|
68
|
+
const value = args[index + 1];
|
|
69
|
+
if (!value || value.startsWith('--')) {
|
|
70
|
+
throw new Error('--engine must be one of official, legacy');
|
|
71
|
+
}
|
|
72
|
+
if (engine !== undefined && engine !== value) {
|
|
73
|
+
throw new Error('--engine must select exactly one of official, legacy');
|
|
74
|
+
}
|
|
75
|
+
engine = value;
|
|
76
|
+
index += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (argument.startsWith('--engine=')) {
|
|
80
|
+
const value = argument.slice('--engine='.length);
|
|
81
|
+
if (engine !== undefined && engine !== value) {
|
|
82
|
+
throw new Error('--engine must select exactly one of official, legacy');
|
|
83
|
+
}
|
|
84
|
+
engine = value;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
forwarded.push(argument);
|
|
88
|
+
}
|
|
89
|
+
if (engine !== undefined && engine !== 'official' && engine !== 'legacy') {
|
|
90
|
+
throw new Error(`--engine must be one of official, legacy; received ${engine}`);
|
|
91
|
+
}
|
|
92
|
+
return { engine: engine ?? 'official', args: forwarded };
|
|
93
|
+
}
|
|
94
|
+
function validateLegacyMetadata(args) {
|
|
95
|
+
let raw;
|
|
96
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
97
|
+
if (args[index] === '--metadata') {
|
|
98
|
+
const value = args[index + 1];
|
|
99
|
+
if (!value || value.startsWith('--')) {
|
|
100
|
+
throw new Error('--metadata must be a JSON object');
|
|
101
|
+
}
|
|
102
|
+
raw = value;
|
|
103
|
+
index += 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (args[index].startsWith('--metadata=')) {
|
|
107
|
+
raw = args[index].slice('--metadata='.length);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
let metadata = {};
|
|
111
|
+
if (raw !== undefined) {
|
|
112
|
+
try {
|
|
113
|
+
// The frozen legacy CLI hands this value directly to json.loads. Do not
|
|
114
|
+
// add @file/path expansion here: only reflection inputs support it.
|
|
115
|
+
metadata = JSON.parse(raw);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
throw new Error('--metadata must be a JSON object containing valid JSON');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (typeof metadata !== 'object' || metadata === null || Array.isArray(metadata)) {
|
|
122
|
+
throw new Error('--metadata must be a JSON object');
|
|
123
|
+
}
|
|
124
|
+
// The frozen CLI consumes the original argv with json.loads. Keep the raw
|
|
125
|
+
// spelling so Python, not JavaScript, owns JSON number precision and adds
|
|
126
|
+
// the selected legacy-engine tag to the run metadata.
|
|
127
|
+
}
|
|
128
|
+
// Parsing starts from an arbitrary command-line string. Keep the literal
|
|
129
|
+
// tuples above checked, then widen only the map boundary used for lookup.
|
|
130
|
+
const VALUE_OPTIONS_BY_FLAG = new Map(VALUE_OPTIONS.map(option => [option.flag, option]));
|
|
131
|
+
const BOOLEAN_OPTIONS_BY_FLAG = new Map(BOOLEAN_OPTIONS.map(([flag, environment, value]) => [flag, { environment, value }]));
|
|
132
|
+
const CONTROLLED_ENVIRONMENT_NAMES = new Set([
|
|
133
|
+
'ORIZU_PROJECT',
|
|
134
|
+
'ORIZU_METADATA',
|
|
135
|
+
...VALUE_OPTIONS.map(option => option.environment),
|
|
136
|
+
...BOOLEAN_OPTIONS.map(([, environment]) => environment),
|
|
137
|
+
'ORIZU_USE_MERGE',
|
|
138
|
+
'ORIZU_MAX_MERGE_INVOCATIONS',
|
|
139
|
+
'ORIZU_SAMPLING_STRATEGY',
|
|
140
|
+
'ORIZU_SELECTION_STRATEGY',
|
|
141
|
+
'ORIZU_MAX_PAYLOAD_CHARS',
|
|
142
|
+
]);
|
|
143
|
+
function optionValueOrThrow(args, index, flag, allowEmpty = false) {
|
|
144
|
+
const argument = args[index];
|
|
145
|
+
const equalsPrefix = `${flag}=`;
|
|
146
|
+
if (argument.startsWith(equalsPrefix)) {
|
|
147
|
+
const value = argument.slice(equalsPrefix.length);
|
|
148
|
+
if ((!allowEmpty && value === '') || value.startsWith('--')) {
|
|
149
|
+
throw new Error(`${flag} requires a value that does not start with --`);
|
|
150
|
+
}
|
|
151
|
+
return { value, nextIndex: index };
|
|
152
|
+
}
|
|
153
|
+
const value = args[index + 1];
|
|
154
|
+
if (value === undefined || value.startsWith('--')) {
|
|
155
|
+
throw new Error(`${flag} requires a value that does not start with --`);
|
|
156
|
+
}
|
|
157
|
+
return { value, nextIndex: index + 1 };
|
|
158
|
+
}
|
|
159
|
+
function translateOfficialOptions(args, project, environment) {
|
|
160
|
+
const connectorEnvironment = { ...environment };
|
|
161
|
+
for (const name of CONTROLLED_ENVIRONMENT_NAMES) {
|
|
162
|
+
delete connectorEnvironment[name];
|
|
163
|
+
}
|
|
164
|
+
connectorEnvironment.ORIZU_PROJECT = project;
|
|
165
|
+
let metadata;
|
|
166
|
+
const budgetFlags = [];
|
|
167
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
168
|
+
const argument = args[index];
|
|
169
|
+
if (!argument.startsWith('--')) {
|
|
170
|
+
throw new Error(`Unexpected run-gepa argument ${argument}`);
|
|
171
|
+
}
|
|
172
|
+
const flag = argument.includes('=') ? argument.slice(0, argument.indexOf('=')) : argument;
|
|
173
|
+
if (flag === '--project') {
|
|
174
|
+
const parsed = optionValueOrThrow(args, index, flag);
|
|
175
|
+
connectorEnvironment.ORIZU_PROJECT = parsed.value;
|
|
176
|
+
index = parsed.nextIndex;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (flag === '--metadata') {
|
|
180
|
+
const parsed = optionValueOrThrow(args, index, flag);
|
|
181
|
+
metadata = parsed.value;
|
|
182
|
+
index = parsed.nextIndex;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const option = VALUE_OPTIONS_BY_FLAG.get(flag);
|
|
186
|
+
if (option) {
|
|
187
|
+
const parsed = optionValueOrThrow(args, index, flag, option.allowEmpty);
|
|
188
|
+
if (flag === '--budget') {
|
|
189
|
+
if (!['auto', 'light', 'medium', 'heavy'].includes(parsed.value)) {
|
|
190
|
+
throw new Error('--budget must be one of auto, light, medium, heavy');
|
|
191
|
+
}
|
|
192
|
+
budgetFlags.push(flag);
|
|
193
|
+
}
|
|
194
|
+
if (['--max-metric-calls', '--max-full-evals', '--max-iterations', '--max-candidate-proposals'].includes(flag)) {
|
|
195
|
+
budgetFlags.push(flag);
|
|
196
|
+
}
|
|
197
|
+
if (flag === '--candidate-selection-strategy' && !['pareto', 'current_best', 'epsilon_greedy'].includes(parsed.value)) {
|
|
198
|
+
throw new Error('--candidate-selection-strategy must be one of pareto, current_best, epsilon_greedy');
|
|
199
|
+
}
|
|
200
|
+
if (flag === '--scorer-input-contract' && !['gepa', 'flat_row'].includes(parsed.value)) {
|
|
201
|
+
throw new Error('--scorer-input-contract must be one of gepa, flat_row');
|
|
202
|
+
}
|
|
203
|
+
connectorEnvironment[option.environment] = option.json
|
|
204
|
+
? jsonObjectValue(parsed.value, option.flag)
|
|
205
|
+
: option.readFile ? textValue(parsed.value) : parsed.value;
|
|
206
|
+
index = parsed.nextIndex;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const boolean = BOOLEAN_OPTIONS_BY_FLAG.get(flag);
|
|
210
|
+
if (boolean) {
|
|
211
|
+
if (argument.includes('=')) {
|
|
212
|
+
throw new Error(`${flag} does not accept a value`);
|
|
213
|
+
}
|
|
214
|
+
if (args[index + 1] !== undefined && !args[index + 1].startsWith('--')) {
|
|
215
|
+
throw new Error(`${flag} does not accept a value`);
|
|
216
|
+
}
|
|
217
|
+
connectorEnvironment[boolean.environment] = boolean.value;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
throw new Error(`Unknown run-gepa option ${flag}`);
|
|
221
|
+
}
|
|
222
|
+
if (budgetFlags.length > 1) {
|
|
223
|
+
throw new Error('Budget options are mutually exclusive; choose at most one of --budget, --max-metric-calls, --max-full-evals, --max-iterations, --max-candidate-proposals');
|
|
224
|
+
}
|
|
225
|
+
const reflectionModel = connectorEnvironment.ORIZU_REFLECTION_MODEL ?? 'anthropic/claude-opus-4-7';
|
|
226
|
+
if (!reflectionModel.startsWith('openai/') && connectorEnvironment.ORIZU_REFLECTION_MAX_TOKENS === undefined) {
|
|
227
|
+
throw new Error('--reflection-max-tokens is required for Anthropic reflection models');
|
|
228
|
+
}
|
|
229
|
+
connectorEnvironment.ORIZU_METADATA = validatedMetadata(metadata);
|
|
230
|
+
return connectorEnvironment;
|
|
231
|
+
}
|
|
232
|
+
function validatedMetadata(raw) {
|
|
233
|
+
if (raw === undefined)
|
|
234
|
+
return '{}';
|
|
235
|
+
try {
|
|
236
|
+
const value = JSON.parse(raw);
|
|
237
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
238
|
+
throw new Error();
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
throw new Error('--metadata must be a JSON object containing valid JSON');
|
|
242
|
+
}
|
|
243
|
+
return raw;
|
|
244
|
+
}
|
|
245
|
+
export function dispatchGepaEngine(args, project, environment) {
|
|
246
|
+
const selected = removeEngine(args);
|
|
247
|
+
if (selected.engine === 'legacy') {
|
|
248
|
+
if (selected.args.some(argument => argument === '--max-candidate-proposals' || argument.startsWith('--max-candidate-proposals='))) {
|
|
249
|
+
throw new Error('--max-candidate-proposals is supported by the official GEPA engine only');
|
|
250
|
+
}
|
|
251
|
+
validateLegacyMetadata(selected.args);
|
|
252
|
+
return {
|
|
253
|
+
engine: 'legacy',
|
|
254
|
+
args: selected.args,
|
|
255
|
+
environment,
|
|
256
|
+
module: 'orizu_gepa.cli',
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const connectorEnvironment = translateOfficialOptions(selected.args, project, environment);
|
|
260
|
+
return { engine: 'official', args: [], environment: connectorEnvironment, module: 'orizu_gepa_connector' };
|
|
261
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function getGepaPythonCommand(args, environment) {
|
|
2
|
+
let python = environment.PYTHON || 'python3';
|
|
3
|
+
const forwarded = [];
|
|
4
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
5
|
+
const argument = args[index];
|
|
6
|
+
if (argument === '--python') {
|
|
7
|
+
const value = args[index + 1];
|
|
8
|
+
if (!value || value.startsWith('--')) {
|
|
9
|
+
throw new Error('--python requires a value that does not start with --');
|
|
10
|
+
}
|
|
11
|
+
python = value;
|
|
12
|
+
index += 1;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (argument.startsWith('--python=')) {
|
|
16
|
+
const value = argument.slice('--python='.length);
|
|
17
|
+
if (!value || value.startsWith('--')) {
|
|
18
|
+
throw new Error('--python requires a value that does not start with --');
|
|
19
|
+
}
|
|
20
|
+
python = value;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
forwarded.push(argument);
|
|
24
|
+
}
|
|
25
|
+
return { python, args: forwarded };
|
|
26
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { isOrizuSourceCheckout } from '../scripts/orizu-source-checkout.mjs';
|
|
4
|
+
function prefersLiveSource() {
|
|
5
|
+
// The source candidates belong to this monorepo only when the candidate
|
|
6
|
+
// root identifies itself as Orizu. A consumer's .git marker is not proof:
|
|
7
|
+
// npm installs commonly live inside another repository.
|
|
8
|
+
return isOrizuSourceCheckout(fileURLToPath(new URL('../../../package.json', import.meta.url)));
|
|
9
|
+
}
|
|
10
|
+
export function resolveGepaPythonPath(candidates, pathExists = existsSync) {
|
|
11
|
+
return candidates.find(pathExists) ?? null;
|
|
12
|
+
}
|
|
13
|
+
export function bundledOrizuGepaPythonPath() {
|
|
14
|
+
const source = fileURLToPath(new URL('../../orizu-gepa-python/src', import.meta.url));
|
|
15
|
+
const vendor = fileURLToPath(new URL('../vendor/orizu-gepa-python/src', import.meta.url));
|
|
16
|
+
const candidates = prefersLiveSource() ? [source, vendor] : [vendor];
|
|
17
|
+
return resolveGepaPythonPath(candidates);
|
|
18
|
+
}
|
|
19
|
+
export function bundledOrizuGepaConnectorPythonPath() {
|
|
20
|
+
const source = fileURLToPath(new URL('../../orizu-gepa/src', import.meta.url));
|
|
21
|
+
const vendor = fileURLToPath(new URL('../vendor/orizu-gepa/src', import.meta.url));
|
|
22
|
+
const candidates = prefersLiveSource() ? [source, vendor] : [vendor];
|
|
23
|
+
return resolveGepaPythonPath(candidates);
|
|
24
|
+
}
|
|
25
|
+
export function bundledOfficialGepaPythonPath() {
|
|
26
|
+
const candidates = [
|
|
27
|
+
fileURLToPath(new URL('../vendor/gepa-python/src', import.meta.url)),
|
|
28
|
+
];
|
|
29
|
+
return resolveGepaPythonPath(candidates);
|
|
30
|
+
}
|
|
31
|
+
export function getGepaPythonPathEntries(existingPythonPath) {
|
|
32
|
+
const pythonPathEntries = [
|
|
33
|
+
bundledOrizuGepaConnectorPythonPath(),
|
|
34
|
+
bundledOrizuGepaPythonPath(),
|
|
35
|
+
bundledOfficialGepaPythonPath(),
|
|
36
|
+
existingPythonPath,
|
|
37
|
+
].filter((entry) => Boolean(entry));
|
|
38
|
+
return pythonPathEntries;
|
|
39
|
+
}
|
package/dist/help.js
CHANGED
|
@@ -343,13 +343,13 @@ export const COMMAND_DOCS = [
|
|
|
343
343
|
},
|
|
344
344
|
{
|
|
345
345
|
path: ['prompts', 'report', 'set'],
|
|
346
|
-
usage: 'orizu prompts report set --prompt <id-or-name> --project <team/project> (--version <n> | --version-id <id>) (--report <markdown|@file> | --report-file <path>) [--json]',
|
|
346
|
+
usage: 'orizu prompts report set --prompt <id-or-name> [--project <team/project>] (--version <n> | --version-id <id>) (--report <markdown|@file> | --report-file <path>) [--json]',
|
|
347
347
|
summary: 'Upload or replace the Markdown report for one explicit prompt version.',
|
|
348
348
|
group: 'Prompts and judges',
|
|
349
349
|
aliases: [['prompts', 'report', 'upload']],
|
|
350
350
|
options: [
|
|
351
351
|
{ name: '--prompt <id-or-name>', help: 'Prompt ID or name.', required: true },
|
|
352
|
-
{ name: '--project <team/project>', help: 'Project slug containing the prompt.'
|
|
352
|
+
{ name: '--project <team/project>', help: 'Project slug containing the prompt.' },
|
|
353
353
|
{ name: '--version <n>', help: 'Positive prompt version number.' },
|
|
354
354
|
{ name: '--version-id <id>', help: 'Explicit prompt version ID.' },
|
|
355
355
|
{ name: '--report <markdown|@file>', help: 'Inline Markdown or an @file reference.' },
|
|
@@ -525,8 +525,8 @@ export const COMMAND_DOCS = [
|
|
|
525
525
|
},
|
|
526
526
|
{
|
|
527
527
|
path: ['optimizations', 'run-gepa'],
|
|
528
|
-
usage: 'orizu optimizations run-gepa --project <team/project> --optimizer-version-id <id> --candidate-version-id <id> --runner-version-id <id> --candidate-runner-dir <dir> --scorer-version-id <id> --scorer-runner-version-id <id> --scorer-runner-dir <dir> [--scorer-input-contract gepa|flat_row] [--scorer-candidate-field <row-field>] [--allow-degenerate-seed] --dataset-version-id <id> --split-set-id <id> [--train-split train] [--val-split validation] [--budget auto|light|medium|heavy | --max-metric-calls <n> | --max-full-evals <n> | --max-iterations <n>] [--num-threads auto|N] [--reflection-retry-attempts N] [--reflection-http-timeout-seconds N] [--log-dir logs]',
|
|
529
|
-
summary: 'Run
|
|
528
|
+
usage: 'orizu optimizations run-gepa --project <team/project> --optimizer-version-id <id> --candidate-version-id <id> --runner-version-id <id> --candidate-runner-dir <dir> --scorer-version-id <id> --scorer-runner-version-id <id> --scorer-runner-dir <dir> [--engine official|legacy] [--scorer-input-contract gepa|flat_row] [--scorer-candidate-field <row-field>] [--allow-degenerate-seed] --dataset-version-id <id> --split-set-id <id> [--train-split train] [--val-split validation] [--budget auto|light|medium|heavy | --max-metric-calls <n> | --max-full-evals <n> | --max-iterations <n> | --max-candidate-proposals <n>] [--num-threads auto|N] [--reflection-retry-attempts N] [--reflection-http-timeout-seconds N] [--log-dir logs]',
|
|
529
|
+
summary: 'Run official GEPA locally and stream events; pass --engine legacy only for the frozen safety hatch. --max-candidate-proposals is official-engine-only. Validates the scorer contract on the seed before iterating; judge runners built for flat-row score runs need --scorer-input-contract flat_row (ALI-1158).',
|
|
530
530
|
group: 'Optimizations',
|
|
531
531
|
},
|
|
532
532
|
{
|
package/dist/index.js
CHANGED
|
@@ -49,9 +49,13 @@ import { runScorersRegister } from './scorer-draft-push.js';
|
|
|
49
49
|
import { runZipArtifactPush } from './zip-draft-push.js';
|
|
50
50
|
import { runGithubLink, runInteractiveHostedSetup } from './github-setup.js';
|
|
51
51
|
import { parseJsonResponse, sanitizeTerminalText } from './json-response.js';
|
|
52
|
+
import { reportReplacementWarning } from './report-replacement-warning.js';
|
|
52
53
|
import { reportCommentsCommand, throwDeprecatedPromptCommentsCommand, } from './report-comments-cli.js';
|
|
53
54
|
import { diffCommentsCommand } from './diff-comments-cli.js';
|
|
54
55
|
import { exportOptimizationRunCommand } from './optimization-export-cli.js';
|
|
56
|
+
import { dispatchGepaEngine } from './gepa-engine-dispatch.js';
|
|
57
|
+
import { getGepaPythonCommand } from './gepa-python-command.js';
|
|
58
|
+
import { getGepaPythonPathEntries } from './gepa-python-paths.js';
|
|
55
59
|
export { parseJsonResponse, sanitizeTerminalText } from './json-response.js';
|
|
56
60
|
function getErrorMessage(error) {
|
|
57
61
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -185,6 +189,14 @@ export function createCodeChallenge(verifier) {
|
|
|
185
189
|
function printError(message) {
|
|
186
190
|
console.error(sanitizeTerminalText(message));
|
|
187
191
|
}
|
|
192
|
+
function printPushDisclosures(data) {
|
|
193
|
+
const warning = reportReplacementWarning(data);
|
|
194
|
+
if (warning)
|
|
195
|
+
printError(warning);
|
|
196
|
+
if (data.metadata_updated === true) {
|
|
197
|
+
printError('Updated prompt metadata on the identical existing version');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
188
200
|
export function validateBrowserUrl(url, expectedOrigin) {
|
|
189
201
|
let parsed;
|
|
190
202
|
try {
|
|
@@ -1014,8 +1026,10 @@ async function pushPromptArtifact(kind) {
|
|
|
1014
1026
|
});
|
|
1015
1027
|
if (hasJsonFlag())
|
|
1016
1028
|
printJson(data);
|
|
1017
|
-
else
|
|
1029
|
+
else {
|
|
1030
|
+
printPushDisclosures(data);
|
|
1018
1031
|
printLine(message);
|
|
1032
|
+
}
|
|
1019
1033
|
return;
|
|
1020
1034
|
}
|
|
1021
1035
|
// LEGACY SESSIONLESS PATH (no branch to commit to; the server dual-writes
|
|
@@ -1061,6 +1075,7 @@ async function pushPromptArtifact(kind) {
|
|
|
1061
1075
|
printJson(data);
|
|
1062
1076
|
return;
|
|
1063
1077
|
}
|
|
1078
|
+
printPushDisclosures(data);
|
|
1064
1079
|
printLine(`Pushed ${kind} ${sanitizeTerminalText(String(manifest.name || promptDir))} (${sanitizeTerminalText(String(data.prompt_version_id || 'unknown version'))})`);
|
|
1065
1080
|
}
|
|
1066
1081
|
async function pullPromptArtifact(kind) {
|
|
@@ -1795,30 +1810,12 @@ async function updateOptimizationRunLifecycle(action) {
|
|
|
1795
1810
|
}
|
|
1796
1811
|
// ALI-1073 list moved to optimizations-list-cli.ts (line ratchet, ALI-976);
|
|
1797
1812
|
// ALI-1175 labels its best scores as agent-reported evidence there.
|
|
1798
|
-
function removeFlagWithValue(args, flag) {
|
|
1799
|
-
const filtered = [];
|
|
1800
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
1801
|
-
if (args[index] === flag) {
|
|
1802
|
-
index += 1;
|
|
1803
|
-
continue;
|
|
1804
|
-
}
|
|
1805
|
-
filtered.push(args[index]);
|
|
1806
|
-
}
|
|
1807
|
-
return filtered;
|
|
1808
|
-
}
|
|
1809
|
-
function bundledOrizuGepaPythonPath() {
|
|
1810
|
-
const candidates = [
|
|
1811
|
-
fileURLToPath(new URL('../vendor/orizu-gepa-python/src', import.meta.url)),
|
|
1812
|
-
fileURLToPath(new URL('../../orizu-gepa-python/src', import.meta.url)),
|
|
1813
|
-
];
|
|
1814
|
-
return candidates.find(candidate => existsSync(candidate)) ?? null;
|
|
1815
|
-
}
|
|
1816
1813
|
async function runGepaOptimization() {
|
|
1817
1814
|
const project = getArg('--project') || await resolveProjectSlug(null);
|
|
1818
1815
|
const baseUrl = getBaseUrl();
|
|
1819
|
-
const
|
|
1820
|
-
const
|
|
1821
|
-
let forwardedArgs =
|
|
1816
|
+
const runGepa = getGepaPythonCommand(cliArgs.slice(2), process.env);
|
|
1817
|
+
const python = runGepa.python;
|
|
1818
|
+
let forwardedArgs = runGepa.args;
|
|
1822
1819
|
// ALI-1159 (ADR-007): GEPA executes ad-hoc local runner dirs while
|
|
1823
1820
|
// attributing records to registered runner version ids — verify the bytes
|
|
1824
1821
|
// ARE those versions before the optimizer spawns. Scans the forwarded argv
|
|
@@ -1828,6 +1825,7 @@ async function runGepaOptimization() {
|
|
|
1828
1825
|
const verified = await verifyGepaRunnerDirsFromArgs(forwardedArgs);
|
|
1829
1826
|
forwardedArgs = verified.args;
|
|
1830
1827
|
let result;
|
|
1828
|
+
let selectedEngine = 'official';
|
|
1831
1829
|
try {
|
|
1832
1830
|
// Uniform resolution (ALI-1090): honors ORIZU_TOKEN / ORIZU_TOKEN_FILE before
|
|
1833
1831
|
// credentials.json so hosted sandboxes can run optimizations. Read at spawn
|
|
@@ -1838,33 +1836,29 @@ async function runGepaOptimization() {
|
|
|
1838
1836
|
if (!forwardedArgs.includes('--project')) {
|
|
1839
1837
|
forwardedArgs = ['--project', project, ...forwardedArgs];
|
|
1840
1838
|
}
|
|
1841
|
-
const
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1839
|
+
const dispatch = dispatchGepaEngine(forwardedArgs, project, {
|
|
1840
|
+
...process.env,
|
|
1841
|
+
ORIZU_API_URL: baseUrl,
|
|
1842
|
+
ORIZU_TOKEN: token,
|
|
1843
|
+
ORIZU_PROJECT: project,
|
|
1844
|
+
ORIZU_VERIFIED_RUNNER_DIRS: JSON.stringify(verified.verifiedDirs),
|
|
1845
|
+
PYTHONPATH: getGepaPythonPathEntries(process.env.PYTHONPATH).join(delimiter),
|
|
1846
|
+
PYTHONUNBUFFERED: process.env.PYTHONUNBUFFERED || '1',
|
|
1847
|
+
});
|
|
1848
|
+
selectedEngine = dispatch.engine;
|
|
1849
|
+
result = spawnSync(python, ['-m', dispatch.module, ...dispatch.args], {
|
|
1846
1850
|
stdio: 'inherit',
|
|
1847
|
-
env:
|
|
1848
|
-
...process.env,
|
|
1849
|
-
ORIZU_API_URL: baseUrl,
|
|
1850
|
-
ORIZU_TOKEN: token,
|
|
1851
|
-
ORIZU_PROJECT: project,
|
|
1852
|
-
// Integrity handshake (ALI-1159): the Python entrypoint refuses
|
|
1853
|
-
// runner dirs that are not in this wrapper-verified list.
|
|
1854
|
-
ORIZU_VERIFIED_RUNNER_DIRS: JSON.stringify(verified.verifiedDirs),
|
|
1855
|
-
PYTHONPATH: pythonPathEntries.join(delimiter),
|
|
1856
|
-
PYTHONUNBUFFERED: process.env.PYTHONUNBUFFERED || '1',
|
|
1857
|
-
},
|
|
1851
|
+
env: dispatch.environment,
|
|
1858
1852
|
});
|
|
1859
1853
|
}
|
|
1860
1854
|
finally {
|
|
1861
1855
|
verified.cleanup();
|
|
1862
1856
|
}
|
|
1863
1857
|
if (result.error) {
|
|
1864
|
-
throw result.error;
|
|
1858
|
+
throw new Error(`${selectedEngine} GEPA engine failed: ${result.error.message}`, { cause: result.error });
|
|
1865
1859
|
}
|
|
1866
1860
|
if (result.status !== 0) {
|
|
1867
|
-
throw new Error(
|
|
1861
|
+
throw new Error(`${selectedEngine} GEPA engine failed with exit code ${result.status}`);
|
|
1868
1862
|
}
|
|
1869
1863
|
if (hasJsonFlag()) {
|
|
1870
1864
|
printJson({ status: 'completed', exitCode: 0 });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import { basename } from 'path';
|
|
3
|
+
import { hasCanonicalReportMarkdownContent } from './report-markdown-blankness.js';
|
|
3
4
|
export const MARKDOWN_REPORT_MAX_BYTES = 2 * 1024 * 1024;
|
|
4
5
|
function getArg(args, name) {
|
|
5
6
|
const index = args.indexOf(name);
|
|
@@ -17,6 +18,11 @@ function rejectDashPrefixedOptionValue(name, value) {
|
|
|
17
18
|
throw new Error(`Invalid value for ${name}: option values cannot start with a dash`);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
21
|
+
function rejectMissingOptionValue(args, name) {
|
|
22
|
+
if (args.some((arg, index) => arg === name && index + 1 >= args.length)) {
|
|
23
|
+
throw new Error(`${name} requires a value`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
20
26
|
function readSourceFile(pathArg) {
|
|
21
27
|
const expandedPath = expandHomePath(pathArg);
|
|
22
28
|
try {
|
|
@@ -31,6 +37,14 @@ function readSourceFile(pathArg) {
|
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
export function readMarkdownReportInput(args, reportLabel) {
|
|
40
|
+
if (args.some(arg => arg.startsWith('--report='))) {
|
|
41
|
+
throw new Error('use --report <markdown|@file> with a space, not =');
|
|
42
|
+
}
|
|
43
|
+
if (args.some(arg => arg.startsWith('--report-file='))) {
|
|
44
|
+
throw new Error('use --report-file <path> with a space, not =');
|
|
45
|
+
}
|
|
46
|
+
rejectMissingOptionValue(args, '--report');
|
|
47
|
+
rejectMissingOptionValue(args, '--report-file');
|
|
34
48
|
const report = getArg(args, '--report');
|
|
35
49
|
const reportFile = getArg(args, '--report-file');
|
|
36
50
|
rejectDashPrefixedOptionValue('--report', report);
|
|
@@ -57,7 +71,7 @@ export function readMarkdownReportInput(args, reportLabel) {
|
|
|
57
71
|
markdown = report || '';
|
|
58
72
|
sourceName = 'inline';
|
|
59
73
|
}
|
|
60
|
-
if (!markdown
|
|
74
|
+
if (!hasCanonicalReportMarkdownContent(markdown)) {
|
|
61
75
|
throw new Error(`${reportLabel} report markdown must not be blank`);
|
|
62
76
|
}
|
|
63
77
|
if (Buffer.byteLength(markdown, 'utf8') > MARKDOWN_REPORT_MAX_BYTES) {
|
|
@@ -19,9 +19,9 @@ export const CLI_LENGTH_MEASUREMENT_UNAVAILABLE_REASONS = [
|
|
|
19
19
|
export function formatFiniteLengthCount(value, signed = false) {
|
|
20
20
|
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
21
21
|
return null;
|
|
22
|
-
const formatted = Math.abs(value).toLocaleString('en-US');
|
|
23
22
|
if (!signed)
|
|
24
|
-
return
|
|
23
|
+
return value.toLocaleString('en-US');
|
|
24
|
+
const formatted = Math.abs(value).toLocaleString('en-US');
|
|
25
25
|
if (value > 0)
|
|
26
26
|
return `+${formatted}`;
|
|
27
27
|
if (value < 0)
|
|
@@ -27,7 +27,7 @@ export async function promptReportCommand(args, context) {
|
|
|
27
27
|
rejectDashPrefixedOptionValue(name, value);
|
|
28
28
|
}
|
|
29
29
|
if (!prompt) {
|
|
30
|
-
throw new Error('Usage: orizu prompts report set --prompt <id-or-name> --project <team/project> ' +
|
|
30
|
+
throw new Error('Usage: orizu prompts report set --prompt <id-or-name> [--project <team/project>] ' +
|
|
31
31
|
'(--version <n> | --version-id <id>) ' +
|
|
32
32
|
'(--report <markdown|@file> | --report-file <path>) [--json]');
|
|
33
33
|
}
|
|
@@ -39,7 +39,7 @@ export async function promptReportCommand(args, context) {
|
|
|
39
39
|
}
|
|
40
40
|
const report = readMarkdownReportInput(args, 'Prompt');
|
|
41
41
|
if (!report) {
|
|
42
|
-
throw new Error('Usage: orizu prompts report set --prompt <id-or-name> --project <team/project> ' +
|
|
42
|
+
throw new Error('Usage: orizu prompts report set --prompt <id-or-name> [--project <team/project>] ' +
|
|
43
43
|
'(--version <n> | --version-id <id>) ' +
|
|
44
44
|
'(--report <markdown|@file> | --report-file <path>) [--json]');
|
|
45
45
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// JavaScript's \s is broader than the database locale's POSIX [:space:]
|
|
2
|
+
// predicate. These four code points are content in the measured PostgreSQL
|
|
3
|
+
// boundary, so retain them explicitly when validating CLI report input.
|
|
4
|
+
export function hasCanonicalReportMarkdownContent(markdown) {
|
|
5
|
+
return /(?:[^\s]|[\u00a0\u2007\u202f\ufeff])/u.test(markdown);
|
|
6
|
+
}
|