orizu 0.3.3 → 0.3.5
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 +19 -0
- package/dist/index.js +359 -20
- package/dist/preview-runtime.js +857 -0
- package/package.json +10 -1
- package/src/index.ts +448 -21
- package/src/preview-runtime.ts +976 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +2 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/optimizer.py +22 -56
- package/vendor/orizu-gepa-python/src/orizu_gepa/reflection.py +31 -6
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { parseDatasetFile } from './file-parser.js'
|
|
|
24
24
|
import { streamJsonlRowChunks } from './jsonl-stream.js'
|
|
25
25
|
import { parseDatasetReference } from './dataset-download.js'
|
|
26
26
|
import { parseGlobalFlags } from './global-flags.js'
|
|
27
|
+
import { runLocalAppPreview } from './preview-runtime.js'
|
|
27
28
|
import {
|
|
28
29
|
assertSecureTokenTransport,
|
|
29
30
|
authedFetch,
|
|
@@ -163,6 +164,12 @@ interface ScorerSummary {
|
|
|
163
164
|
implementationKind: string
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
interface ScoreSubmitInput {
|
|
168
|
+
resultsJsonl?: string
|
|
169
|
+
aggregate?: Record<string, unknown>
|
|
170
|
+
aggregateWarning?: string
|
|
171
|
+
}
|
|
172
|
+
|
|
166
173
|
interface RunnerExecContext {
|
|
167
174
|
prompt: {
|
|
168
175
|
body: string | null
|
|
@@ -185,6 +192,8 @@ interface RunnerExecContext {
|
|
|
185
192
|
|
|
186
193
|
type DatasetUploadSourceType = 'csv' | 'json' | 'jsonl'
|
|
187
194
|
|
|
195
|
+
const MAX_README_LENGTH = 200_000
|
|
196
|
+
|
|
188
197
|
interface DatasetUploadResponse {
|
|
189
198
|
dataset: {
|
|
190
199
|
id: string
|
|
@@ -193,6 +202,11 @@ interface DatasetUploadResponse {
|
|
|
193
202
|
sourceType: string
|
|
194
203
|
url?: string
|
|
195
204
|
}
|
|
205
|
+
readmeVersion?: {
|
|
206
|
+
id: string
|
|
207
|
+
version_num: number
|
|
208
|
+
created_at: string
|
|
209
|
+
} | null
|
|
196
210
|
}
|
|
197
211
|
|
|
198
212
|
interface TeamMember {
|
|
@@ -256,11 +270,16 @@ function printVersion() {
|
|
|
256
270
|
}
|
|
257
271
|
|
|
258
272
|
function printUsage() {
|
|
259
|
-
printLine(`orizu global options:\n\n --local Use http://localhost:3000\n --server <url> Use a specific server origin (for example: https://preview.example.com)\n --version, -v Print the orizu CLI version\n\norizu commands:\n\n orizu login [--no-prompt-if-logged-in]\n orizu logout\n orizu whoami\n orizu env [--project <team/project>] [--project-id <projectId>]\n orizu log <event_type> --run-id <id> --sequence <n> --payload @event.json\n orizu teams list\n orizu teams create [--name <name>]\n orizu teams members list [--team <teamSlug>]\n orizu teams members add --email <email> [--team <teamSlug>]\n orizu teams members remove --email <email> [--team <teamSlug>]\n orizu teams members role --team <teamSlug> --email <email> --role <admin|member>\n orizu projects list [--team <teamSlug>]\n orizu projects create --name <name> [--team <teamSlug>]\n orizu prompts list --project <team/project>\n orizu prompts comments <prompt-id-or-name> --project <team/project> [--label <label> | --version <id>] [--json]\n orizu prompts pull <prompt-id-or-name> --project <team/project> --out <dir> [--label <label> | --version <id>] [--json]\n orizu prompts push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--json]\n orizu prompts labels set <prompt-name> <label> --version <version-id> [--project <team/project>] [--json]\n orizu prompts scorers set-headline <prompt-id> --scorer-version <id> [--dataset-version <id> --split-set <id> --split <name>] [--project <team/project>] [--json]\n orizu prompts scorers add <prompt-id> --scorer-version <id> [--dataset-version <id> --split-set <id> --split <name>] [--project <team/project>] [--json]\n orizu scorers list --project <team/project>\n orizu scorers register --project <team/project> --name <name> --manifest <manifest.json> [--prompt-version <id>] [--runner-version <id>] [--label <label>] [--json]\n orizu scorers detail <scorer-id-or-name> --project <team/project> [--json]\n orizu scorers labels set <scorer-name> <label> --version <scorer-version-id> [--project <team/project>] [--json]\n orizu scores submit <results.jsonl|results.json> --scorer-version <id> --subject-version <prompt-version-id> [--dataset-version <id> --split-set <id> --split <name>] [--project <team/project>] [--json]\n orizu judges list --project <team/project>\n orizu judges pull <judge-id-or-name> --project <team/project> --out <dir> [--label <label> | --version <id>] [--json]\n orizu judges push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--json]\n orizu runners push <dir> [--project <team/project>] [--name <name>] [--label <label>] [--json]\n orizu runners exec (--prompt <prompt-version-id> | --prompt-version <id> --runner-version <id> | --scorer-version <id>) --dataset-version <id> --split-set <id-or-name> --split <name> [--runner-dir <dir>] --out <results.jsonl|results.jsonl.gz>\n orizu optimizers push <dir> [--project <team/project>] [--name <name>] [--label <label>] [--json]\n orizu runs submit <results.jsonl|results.jsonl.gz> --prompt-version <id> --runner-version <id> --dataset-version <id> --split-set <id> --split <name> [--project <team/project>]\n orizu apps list [--project <team/project>]\n orizu apps create --project <team/project> --name <name> --dataset <datasetId> --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps update [--app <appId>] [--project <team/project>] --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps link-dataset --dataset <datasetId> [--app <appId>] [--project <team/project>] [--version <n>]\n orizu apps detail --app <appId> [--project <team/project>] [--json]\n orizu tasks list [--project <team/project>]\n orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> --assignees <userIdOrEmail1,userIdOrEmail2> [--version <n>] [--instructions <text>] [--labels-per-item <n>] [--json]\n orizu tasks assign --task <taskId> --assignees <userId1,userId2>\n orizu tasks status --task <taskId> [--json]\n orizu tasks pause --task <taskId>\n orizu tasks unpause --task <taskId>\n orizu datasets upload --file <path> [--project <team/project>] [--name <name>]\n orizu datasets push <path> [--project <team/project>] [--name <name>] [--json]\n orizu datasets versions create <datasetId|dataset-name> [--project <team/project>] [--label <label>] [--json]\n orizu datasets splits create <datasetVersionId> [--from-file <split.json>] [--json]\n orizu datasets download [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--format <csv|json|jsonl>] [--out <path>]\n orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets edit-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --row-ids <id1,id2>\n orizu datasets delete [--dataset <datasetId|datasetUrl>] [--project <team/project>]\n orizu datasets lock [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--reason <text>]\n orizu datasets clone [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--name <name>]\n orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]`)
|
|
273
|
+
printLine(`orizu global options:\n\n --local Use http://localhost:3000\n --server <url> Use a specific server origin (for example: https://preview.example.com)\n --version, -v Print the orizu CLI version\n\norizu commands:\n\n orizu login [--no-prompt-if-logged-in]\n orizu logout\n orizu whoami\n orizu env [--project <team/project>] [--project-id <projectId>]\n orizu log <event_type> --run-id <id> --sequence <n> --payload @event.json\n orizu teams list\n orizu teams create [--name <name>]\n orizu teams members list [--team <teamSlug>]\n orizu teams members add --email <email> [--team <teamSlug>]\n orizu teams members remove --email <email> [--team <teamSlug>]\n orizu teams members role --team <teamSlug> --email <email> --role <admin|member>\n orizu projects list [--team <teamSlug>]\n orizu projects create --name <name> [--team <teamSlug>]\n orizu prompts list --project <team/project>\n orizu prompts comments <prompt-id-or-name> --project <team/project> [--label <label> | --version <id>] [--json]\n orizu prompts pull <prompt-id-or-name> --project <team/project> --out <dir> [--label <label> | --version <id>] [--json]\n orizu prompts push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--json]\n orizu prompts labels set <prompt-name> <label> --version <version-id> [--project <team/project>] [--json]\n orizu prompts scorers set-headline <prompt-id> --scorer-version <id> [--dataset-version <id> --split-set <id> --split <name>] [--project <team/project>] [--json]\n orizu prompts scorers add <prompt-id> --scorer-version <id> [--dataset-version <id> --split-set <id> --split <name>] [--project <team/project>] [--json]\n orizu scorers list --project <team/project>\n orizu scorers register --project <team/project> --name <name> --manifest <manifest.json> [--prompt-version <id>] [--runner-version <id>] [--label <label>] [--json]\n orizu scorers detail <scorer-id-or-name> --project <team/project> [--json]\n orizu scorers labels set <scorer-name> <label> --version <scorer-version-id> [--project <team/project>] [--json]\n orizu scorers exec --scorer-version <id> (--subject-version <prompt-version-id> | --optimization-run <id> --candidate <id>) --dataset-version <id> --split-set <id> --split <name> [--subject-results <jsonl>] [--dependency-score-run <alias=id>] [--dependency-results <alias=path>] [--no-submit] [--out <score.json>] [--project <team/project>] [--json]\n orizu scores submit <results.jsonl|results.json> --scorer-version <id> (--subject-version <prompt-version-id> | --optimization-run <id> --candidate <id>) [--aggregate] [--dataset-version <id> --split-set <id> --split <name>] [--project <team/project>] [--json]\n orizu judges list --project <team/project>\n orizu judges pull <judge-id-or-name> --project <team/project> --out <dir> [--label <label> | --version <id>] [--json]\n orizu judges push <dir> [--runner-version <id>] [--project <team/project>] [--parent <version-id>] [--json]\n orizu runners push <dir> [--project <team/project>] [--name <name>] [--label <label>] [--json]\n orizu runners exec (--prompt <prompt-version-id> | --prompt-version <id> --runner-version <id> | --scorer-version <id>) --dataset-version <id> --split-set <id-or-name> --split <name> [--runner-dir <dir>] --out <results.jsonl|results.jsonl.gz>\n orizu optimizers push <dir> [--project <team/project>] [--name <name>] [--label <label>] [--json]\n orizu runs submit <results.jsonl|results.jsonl.gz> --prompt-version <id> --runner-version <id> --dataset-version <id> --split-set <id> --split <name> [--project <team/project>]\n orizu apps list [--project <team/project>]\n orizu apps create --project <team/project> --name <name> --dataset <datasetId> --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps update [--app <appId>] [--project <team/project>] --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps link-dataset --dataset <datasetId> [--app <appId>] [--project <team/project>] [--version <n>]\n orizu apps detail --app <appId> [--project <team/project>] [--json]\n orizu apps export [--app <appId>] [--project <team/project>] [--version <n>] [--out <path>]\n orizu tasks list [--project <team/project>]\n orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> --assignees <userIdOrEmail1,userIdOrEmail2> [--version <n>] [--instructions <text>] [--labels-per-item <n>] [--json]\n orizu tasks assign --task <taskId> --assignees <userId1,userId2>\n orizu tasks status --task <taskId> [--json]\n orizu tasks pause --task <taskId>\n orizu tasks unpause --task <taskId>\n orizu datasets upload --file <path> [--project <team/project>] [--name <name>] [--readme-file <README.md> | --readme-text <markdown>]\n orizu datasets push <path> [--project <team/project>] [--name <name>] [--readme-file <README.md> | --readme-text <markdown>] [--json]\n orizu datasets readme set <datasetId|dataset-name> [--project <team/project>] (--readme-file <README.md> | --readme-text <markdown>) [--json]\n orizu datasets versions create <datasetId|dataset-name> [--project <team/project>] [--label <label>] [--readme-file <README.md> | --readme-text <markdown>] [--json]\n orizu datasets splits create <datasetVersionId> [--from-file <split.json>] [--json]\n orizu datasets download [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--format <csv|json|jsonl>] [--out <path>]\n orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets edit-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --row-ids <id1,id2>\n orizu datasets delete [--dataset <datasetId|datasetUrl>] [--project <team/project>]\n orizu datasets lock [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--reason <text>]\n orizu datasets clone [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--name <name>]\n orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]`)
|
|
274
|
+
printPreviewUsage()
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function printPreviewUsage() {
|
|
278
|
+
printLine(`\nLocal app preview:\n\n orizu apps preview --file <path> --input-schema <json-path> --output-schema <json-path> --sample-row <json-path> [--screenshot <png-path>] [--headed] [--keep-open] [--component <name>]`)
|
|
260
279
|
}
|
|
261
280
|
|
|
262
281
|
function printOptimizationUsage() {
|
|
263
|
-
printLine(`\nOptimization lifecycle commands:\n\n orizu optimizations start --project <team/project> --optimizer-version <id> --prompt-version <id[,id]> --selection-scorer <id> [--reflection-scorer <id>] [--pareto-scorer <id>] [--best-scorer <id>] --dataset-version <id> --split-set <id> [--train-split <name>] [--validation-split <name>] [--metadata <json|@file>] [--json]\n 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> --dataset-version-id <id> --split-set-id <id> [--train-split train] [--val-split validation] [--log-dir logs]\n orizu optimizations export <run-id> [--out <path>] [--json]\n orizu optimizations pause <run-id> [--reason <text>] [--json]\n orizu optimizations resume <run-id> [--json]\n orizu optimizations finish <run-id> [--best-score <n>] [--best-candidate <id>] [--result-prompt-version <id>] [--metadata <json|@file>] [--json]\n orizu optimizations fail <run-id> [--reason <text>] [--metadata <json|@file>] [--json]\n orizu optimizations cancel <run-id> [--reason <text>] [--json]`)
|
|
282
|
+
printLine(`\nOptimization lifecycle commands:\n\n orizu optimizations start --project <team/project> --optimizer-version <id> --prompt-version <id[,id]> --selection-scorer <id> [--reflection-scorer <id>] [--pareto-scorer <id>] [--best-scorer <id>] --dataset-version <id> --split-set <id> [--train-split <name>] [--validation-split <name>] [--metadata <json|@file>] [--json]\n 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> --dataset-version-id <id> --split-set-id <id> [--train-split train] [--val-split validation] [--log-dir logs]\n orizu optimizations export <run-id> [--out <path>] [--json]\n orizu optimizations pause <run-id> [--reason <text>] [--json]\n orizu optimizations resume <run-id> [--json]\n orizu optimizations finish <run-id> [--best-score <n>] [--best-candidate <id>] [--result-prompt-version <id>] [--report <markdown|@file> | --report-file <path>] [--metadata <json|@file>] [--json]\n orizu optimizations fail <run-id> [--reason <text>] [--report <markdown|@file> | --report-file <path>] [--metadata <json|@file>] [--json]\n orizu optimizations cancel <run-id> [--reason <text>] [--report <markdown|@file> | --report-file <path>] [--json]`)
|
|
264
283
|
}
|
|
265
284
|
|
|
266
285
|
let cliArgs = process.argv.slice(2)
|
|
@@ -295,6 +314,25 @@ export function expandHomePath(path: string): string {
|
|
|
295
314
|
return path
|
|
296
315
|
}
|
|
297
316
|
|
|
317
|
+
function readReadmeMarkdownFromArgs(usage: string): string | null {
|
|
318
|
+
const readmeFile = getArg('--readme-file')
|
|
319
|
+
const readmeText = getArg('--readme-text')
|
|
320
|
+
|
|
321
|
+
if (readmeFile !== null && readmeText !== null) {
|
|
322
|
+
throw new Error(`Use either --readme-file or --readme-text, not both.\n${usage}`)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const markdown = readmeFile !== null
|
|
326
|
+
? readFileSync(expandHomePath(readmeFile), 'utf8')
|
|
327
|
+
: readmeText
|
|
328
|
+
|
|
329
|
+
if (markdown !== null && markdown.length > MAX_README_LENGTH) {
|
|
330
|
+
throw new Error(`README markdown is too large. Maximum size is ${MAX_README_LENGTH} characters.`)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return markdown
|
|
334
|
+
}
|
|
335
|
+
|
|
298
336
|
function createCodeVerifier(): string {
|
|
299
337
|
return randomBytes(32).toString('base64url')
|
|
300
338
|
}
|
|
@@ -1807,16 +1845,21 @@ async function createDatasetVersion() {
|
|
|
1807
1845
|
const datasetId = getPositionalArg(3) || getArg('--dataset')
|
|
1808
1846
|
const versionLabel = getArg('--label') || getArg('--version-label') || null
|
|
1809
1847
|
const project = getArg('--project')
|
|
1848
|
+
const usage = 'Usage: orizu datasets versions create <datasetId|dataset-name> [--project <team/project>] [--label <label>] [--readme-file <README.md> | --readme-text <markdown>] [--json]'
|
|
1810
1849
|
|
|
1811
1850
|
if (!datasetId) {
|
|
1812
|
-
throw new Error(
|
|
1851
|
+
throw new Error(usage)
|
|
1813
1852
|
}
|
|
1814
1853
|
|
|
1854
|
+
const readmeMarkdown = readReadmeMarkdownFromArgs(usage)
|
|
1815
1855
|
const resolvedDatasetId = await resolveDatasetIdForProject(datasetId, project)
|
|
1816
1856
|
const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(resolvedDatasetId)}/versions`, {
|
|
1817
1857
|
method: 'POST',
|
|
1818
1858
|
headers: { 'Content-Type': 'application/json' },
|
|
1819
|
-
body: JSON.stringify({
|
|
1859
|
+
body: JSON.stringify({
|
|
1860
|
+
versionLabel,
|
|
1861
|
+
...(readmeMarkdown !== null ? { readmeMarkdown } : {}),
|
|
1862
|
+
}),
|
|
1820
1863
|
})
|
|
1821
1864
|
|
|
1822
1865
|
if (!response.ok) {
|
|
@@ -1970,18 +2013,23 @@ async function submitScoreResults() {
|
|
|
1970
2013
|
const candidateId = getArg('--candidate')
|
|
1971
2014
|
|
|
1972
2015
|
if (!resultsPath || !scorerVersionId || (!subjectPromptVersionId && (!optimizationRunId || !candidateId))) {
|
|
1973
|
-
throw new Error('Usage: orizu scores submit <results.jsonl|results.json> --project <team/project> --scorer-version <id> (--subject-version <prompt-version-id> | --optimization-run <id> --candidate <id>) [--dataset-version <id> --split-set <id> --split <name>] [--json]')
|
|
2016
|
+
throw new Error('Usage: orizu scores submit <results.jsonl|results.json> --project <team/project> --scorer-version <id> (--subject-version <prompt-version-id> | --optimization-run <id> --candidate <id>) [--aggregate] [--dataset-version <id> --split-set <id> --split <name>] [--json]')
|
|
1974
2017
|
}
|
|
1975
2018
|
|
|
1976
2019
|
const resultBytes = readSourceBytes(resultsPath)
|
|
1977
2020
|
const raw = resultsPath.endsWith('.gz')
|
|
1978
2021
|
? gunzipSync(resultBytes).toString('utf8')
|
|
1979
2022
|
: resultBytes.toString('utf8')
|
|
1980
|
-
const
|
|
2023
|
+
const scoreInput = normalizeScoreResultsInput(resultsPath, raw, hasArg('--aggregate'))
|
|
2024
|
+
if (scoreInput.aggregateWarning) {
|
|
2025
|
+
console.warn(scoreInput.aggregateWarning)
|
|
2026
|
+
}
|
|
2027
|
+
const aggregatePayload = scoreInput.aggregate || {}
|
|
1981
2028
|
const response = await authedFetch(`/api/cli/scores/submit?project=${encodeURIComponent(project)}`, {
|
|
1982
2029
|
method: 'POST',
|
|
1983
2030
|
headers: { 'Content-Type': 'application/json' },
|
|
1984
2031
|
body: JSON.stringify({
|
|
2032
|
+
...aggregatePayload,
|
|
1985
2033
|
scorerVersionId,
|
|
1986
2034
|
subjectPromptVersionId: subjectPromptVersionId || undefined,
|
|
1987
2035
|
datasetVersionId: getArg('--dataset-version') || undefined,
|
|
@@ -1989,7 +2037,7 @@ async function submitScoreResults() {
|
|
|
1989
2037
|
splitName: getArg('--split') || undefined,
|
|
1990
2038
|
optimizationRunId: optimizationRunId || undefined,
|
|
1991
2039
|
candidateId: candidateId || undefined,
|
|
1992
|
-
resultsJsonl,
|
|
2040
|
+
resultsJsonl: scoreInput.resultsJsonl,
|
|
1993
2041
|
}),
|
|
1994
2042
|
})
|
|
1995
2043
|
|
|
@@ -2015,24 +2063,161 @@ async function submitScoreResults() {
|
|
|
2015
2063
|
)
|
|
2016
2064
|
}
|
|
2017
2065
|
|
|
2018
|
-
function
|
|
2066
|
+
function looksLikeAggregateScoreObject(value: Record<string, unknown>): boolean {
|
|
2067
|
+
return (
|
|
2068
|
+
value.scoreValue !== undefined ||
|
|
2069
|
+
value.score_value !== undefined ||
|
|
2070
|
+
value.diagnostics !== undefined ||
|
|
2071
|
+
value.feedbackSummary !== undefined ||
|
|
2072
|
+
value.feedback_summary !== undefined ||
|
|
2073
|
+
value.rowEvidence !== undefined ||
|
|
2074
|
+
value.row_evidence !== undefined ||
|
|
2075
|
+
value.dependencyScoreRunIds !== undefined ||
|
|
2076
|
+
value.dependency_score_run_ids !== undefined
|
|
2077
|
+
)
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
function numberFromUnknown(value: unknown): number | null {
|
|
2081
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value
|
|
2082
|
+
if (typeof value === 'string' && value.trim()) {
|
|
2083
|
+
const parsed = Number(value)
|
|
2084
|
+
return Number.isFinite(parsed) ? parsed : null
|
|
2085
|
+
}
|
|
2086
|
+
if (typeof value === 'boolean') return value ? 1 : 0
|
|
2087
|
+
return null
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
function normalizeScoreResultsInput(sourcePath: string, raw: string, aggregateMode = false): ScoreSubmitInput {
|
|
2019
2091
|
const logicalPath = sourcePath.endsWith('.gz') ? sourcePath.slice(0, -3) : sourcePath
|
|
2020
|
-
if (!logicalPath.endsWith('.json')) return raw
|
|
2092
|
+
if (!logicalPath.endsWith('.json')) return { resultsJsonl: raw }
|
|
2021
2093
|
|
|
2022
2094
|
try {
|
|
2023
2095
|
const parsed = JSON.parse(raw) as unknown
|
|
2096
|
+
if (aggregateMode) {
|
|
2097
|
+
if (!isRecord(parsed)) {
|
|
2098
|
+
throw new Error('Aggregate score results JSON must be an object')
|
|
2099
|
+
}
|
|
2100
|
+
return { aggregate: parsed }
|
|
2101
|
+
}
|
|
2102
|
+
if (isRecord(parsed) && looksLikeAggregateScoreObject(parsed)) {
|
|
2103
|
+
return {
|
|
2104
|
+
aggregate: parsed,
|
|
2105
|
+
aggregateWarning: 'Warning: aggregate score JSON detected. Pass --aggregate to make this explicit.',
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2024
2108
|
const rows = Array.isArray(parsed) ? parsed : [parsed]
|
|
2025
2109
|
if (rows.some(row => !isRecord(row))) {
|
|
2026
2110
|
throw new Error('JSON score results must be an object or an array of objects')
|
|
2027
2111
|
}
|
|
2028
|
-
return rows.map(row => JSON.stringify(row)).join('\n')
|
|
2112
|
+
return { resultsJsonl: rows.map(row => JSON.stringify(row)).join('\n') }
|
|
2029
2113
|
} catch (error) {
|
|
2030
2114
|
const message = error instanceof Error ? error.message : String(error)
|
|
2031
2115
|
throw new Error(`Invalid score results JSON '${sourcePath}': ${message}`)
|
|
2032
2116
|
}
|
|
2033
2117
|
}
|
|
2034
2118
|
|
|
2119
|
+
function readOptionalJsonlFile(pathArg: string | null): string | undefined {
|
|
2120
|
+
if (!pathArg) return undefined
|
|
2121
|
+
const bytes = readSourceBytes(pathArg)
|
|
2122
|
+
return pathArg.endsWith('.gz')
|
|
2123
|
+
? gunzipSync(bytes).toString('utf8')
|
|
2124
|
+
: bytes.toString('utf8')
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
function parseAliasAssignments(value: string | null): Record<string, string> {
|
|
2128
|
+
const result: Record<string, string> = {}
|
|
2129
|
+
if (!value) return result
|
|
2130
|
+
for (const item of parseCommaSeparated(value)) {
|
|
2131
|
+
const equalsIndex = item.indexOf('=')
|
|
2132
|
+
if (equalsIndex <= 0 || equalsIndex === item.length - 1) {
|
|
2133
|
+
throw new Error(`Expected alias assignment in form alias=value, got '${item}'`)
|
|
2134
|
+
}
|
|
2135
|
+
result[item.slice(0, equalsIndex)] = item.slice(equalsIndex + 1)
|
|
2136
|
+
}
|
|
2137
|
+
return result
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
function readDependencyResultAssignments(value: string | null): Record<string, string> | undefined {
|
|
2141
|
+
const assignments = parseAliasAssignments(value)
|
|
2142
|
+
const result: Record<string, string> = {}
|
|
2143
|
+
for (const [alias, path] of Object.entries(assignments)) {
|
|
2144
|
+
result[alias] = readOptionalJsonlFile(path) || ''
|
|
2145
|
+
}
|
|
2146
|
+
return Object.keys(result).length > 0 ? result : undefined
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
async function execScorer() {
|
|
2150
|
+
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
2151
|
+
const scorerVersionId = getArg('--scorer-version')
|
|
2152
|
+
const subjectPromptVersionId = getArg('--subject-version') || getArg('--prompt-version')
|
|
2153
|
+
const optimizationRunId = getArg('--optimization-run')
|
|
2154
|
+
const candidateId = getArg('--candidate')
|
|
2155
|
+
const datasetVersionId = getArg('--dataset-version')
|
|
2156
|
+
const splitSetId = getArg('--split-set')
|
|
2157
|
+
const splitName = getArg('--split')
|
|
2158
|
+
const outPath = getArg('--out')
|
|
2159
|
+
|
|
2160
|
+
if (
|
|
2161
|
+
!scorerVersionId ||
|
|
2162
|
+
(!subjectPromptVersionId && (!optimizationRunId || !candidateId)) ||
|
|
2163
|
+
!datasetVersionId ||
|
|
2164
|
+
!splitSetId ||
|
|
2165
|
+
!splitName
|
|
2166
|
+
) {
|
|
2167
|
+
throw new Error('Usage: orizu scorers exec --scorer-version <id> (--subject-version <prompt-version-id> | --optimization-run <id> --candidate <id>) --dataset-version <id> --split-set <id> --split <name> [--subject-results <jsonl>] [--dependency-score-run <alias=id>] [--dependency-results <alias=path>] [--no-submit] [--out <score.json>] [--project <team/project>] [--json]')
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
const response = await authedFetch(`/api/cli/scorers/exec?project=${encodeURIComponent(project)}`, {
|
|
2171
|
+
method: 'POST',
|
|
2172
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2173
|
+
body: JSON.stringify({
|
|
2174
|
+
scorerVersionId,
|
|
2175
|
+
subjectPromptVersionId: subjectPromptVersionId || undefined,
|
|
2176
|
+
optimizationRunId: optimizationRunId || undefined,
|
|
2177
|
+
candidateId: candidateId || undefined,
|
|
2178
|
+
datasetVersionId,
|
|
2179
|
+
splitSetId,
|
|
2180
|
+
splitName,
|
|
2181
|
+
submit: !hasArg('--no-submit'),
|
|
2182
|
+
reuseExisting: !hasArg('--no-reuse-existing'),
|
|
2183
|
+
subjectResultsJsonl: readOptionalJsonlFile(getArg('--subject-results') || getArg('--outputs')),
|
|
2184
|
+
dependencyScoreRunIds: parseAliasAssignments(getArg('--dependency-score-run') || getArg('--dependency-score-runs')),
|
|
2185
|
+
dependencyResultsJsonl: readDependencyResultAssignments(getArg('--dependency-results')),
|
|
2186
|
+
}),
|
|
2187
|
+
})
|
|
2188
|
+
|
|
2189
|
+
if (!response.ok) {
|
|
2190
|
+
throw new Error(`Failed to execute scorer: ${await response.text()}`)
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
const data = await parseJsonResponse<Record<string, unknown>>(response, 'Scorer exec')
|
|
2194
|
+
if (outPath) {
|
|
2195
|
+
writeFileSync(expandHomePath(outPath), `${JSON.stringify(data.scoreResult || data, null, 2)}\n`)
|
|
2196
|
+
}
|
|
2197
|
+
if (hasJsonFlag()) {
|
|
2198
|
+
printJson(data)
|
|
2199
|
+
return
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
const scoreRun = isRecord(data.scoreRun) ? data.scoreRun : null
|
|
2203
|
+
const scoreResult = isRecord(data.scoreResult) ? data.scoreResult : null
|
|
2204
|
+
const scoreValue = scoreRun
|
|
2205
|
+
? scoreRun.scoreValue
|
|
2206
|
+
: scoreResult
|
|
2207
|
+
? scoreResult.scoreValue
|
|
2208
|
+
: null
|
|
2209
|
+
if (scoreRun && typeof scoreRun.id === 'string') {
|
|
2210
|
+
printLine(`Executed scorer ${sanitizeTerminalText(scorerVersionId)} -> score ${sanitizeTerminalText(scoreRun.id)} (${formatPercent(numberFromUnknown(scoreValue))})`)
|
|
2211
|
+
} else {
|
|
2212
|
+
printLine(`Executed scorer ${sanitizeTerminalText(scorerVersionId)} (${formatPercent(numberFromUnknown(scoreValue))})`)
|
|
2213
|
+
}
|
|
2214
|
+
if (outPath) {
|
|
2215
|
+
printLine(`Wrote scorer result to ${sanitizeTerminalText(outPath)}`)
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2035
2219
|
type OptimizationLifecycleAction = 'pause' | 'resume' | 'finish' | 'fail' | 'cancel'
|
|
2220
|
+
const OPTIMIZATION_REPORT_MAX_BYTES = 2 * 1024 * 1024
|
|
2036
2221
|
|
|
2037
2222
|
function parseOptionalNumberFlag(name: string): number | undefined {
|
|
2038
2223
|
const value = getArg(name)
|
|
@@ -2052,6 +2237,46 @@ function hasObjectKeys(value: Record<string, unknown>): boolean {
|
|
|
2052
2237
|
return Object.keys(value).length > 0
|
|
2053
2238
|
}
|
|
2054
2239
|
|
|
2240
|
+
function readOptimizationReportInput(): { markdown: string; sourceName: string | null } | null {
|
|
2241
|
+
const report = getArg('--report')
|
|
2242
|
+
const reportFile = getArg('--report-file')
|
|
2243
|
+
|
|
2244
|
+
if (report && reportFile) {
|
|
2245
|
+
throw new Error('Use either --report or --report-file, not both')
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
if (!report && !reportFile) {
|
|
2249
|
+
return null
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
let markdown: string
|
|
2253
|
+
let sourceName: string | null
|
|
2254
|
+
|
|
2255
|
+
if (reportFile) {
|
|
2256
|
+
const expandedPath = expandHomePath(reportFile)
|
|
2257
|
+
markdown = readSourceFile(reportFile)
|
|
2258
|
+
sourceName = basename(expandedPath)
|
|
2259
|
+
} else if (report?.startsWith('@')) {
|
|
2260
|
+
const path = report.slice(1)
|
|
2261
|
+
const expandedPath = expandHomePath(path)
|
|
2262
|
+
markdown = readSourceFile(path)
|
|
2263
|
+
sourceName = basename(expandedPath)
|
|
2264
|
+
} else {
|
|
2265
|
+
markdown = report || ''
|
|
2266
|
+
sourceName = 'inline'
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
if (!markdown.trim()) {
|
|
2270
|
+
throw new Error('Optimization report markdown must not be blank')
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
if (Buffer.byteLength(markdown, 'utf8') > OPTIMIZATION_REPORT_MAX_BYTES) {
|
|
2274
|
+
throw new Error(`Optimization report exceeds ${OPTIMIZATION_REPORT_MAX_BYTES} bytes`)
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
return { markdown, sourceName }
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2055
2280
|
async function startOptimizationRun() {
|
|
2056
2281
|
const project = getArg('--project') || await resolveProjectSlug(null)
|
|
2057
2282
|
const optimizerVersionId = getArg('--optimizer-version')
|
|
@@ -2156,6 +2381,11 @@ async function updateOptimizationRunLifecycle(action: OptimizationLifecycleActio
|
|
|
2156
2381
|
}
|
|
2157
2382
|
const metadata = readJsonObjectArg(getArg('--metadata'), 'optimization metadata')
|
|
2158
2383
|
const reason = getArg('--reason')
|
|
2384
|
+
const report = readOptimizationReportInput()
|
|
2385
|
+
|
|
2386
|
+
if (report && (action === 'pause' || action === 'resume')) {
|
|
2387
|
+
throw new Error(`orizu optimizations ${action} does not accept optimization reports`)
|
|
2388
|
+
}
|
|
2159
2389
|
|
|
2160
2390
|
if ((action === 'pause' || action === 'cancel') && reason) {
|
|
2161
2391
|
metadata.reason = reason
|
|
@@ -2170,6 +2400,11 @@ async function updateOptimizationRunLifecycle(action: OptimizationLifecycleActio
|
|
|
2170
2400
|
body.metadata = metadata
|
|
2171
2401
|
}
|
|
2172
2402
|
|
|
2403
|
+
if (report) {
|
|
2404
|
+
body.reportMarkdown = report.markdown
|
|
2405
|
+
body.reportSourceName = report.sourceName
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2173
2408
|
if (action === 'finish') {
|
|
2174
2409
|
const bestScore = parseOptionalNumberFlag('--best-score')
|
|
2175
2410
|
if (bestScore !== undefined) {
|
|
@@ -2707,15 +2942,61 @@ async function createAppFromFile() {
|
|
|
2707
2942
|
}
|
|
2708
2943
|
|
|
2709
2944
|
const data = await parseJsonResponse<{
|
|
2710
|
-
app: { id: string; name: string; versionNum: number; componentName?: string }
|
|
2945
|
+
app: { id: string; name: string; versionNum: number; componentName?: string; url?: string }
|
|
2711
2946
|
warnings?: string[]
|
|
2712
2947
|
}>(response, 'App create')
|
|
2713
2948
|
printLine(`Created app ${sanitizeTerminalText(data.app.name)} (${sanitizeTerminalText(data.app.id)}) v${data.app.versionNum}`)
|
|
2949
|
+
if (data.app.url) {
|
|
2950
|
+
printLine(`View app: ${formatTerminalLink(data.app.url)}`)
|
|
2951
|
+
}
|
|
2714
2952
|
if (data.warnings?.length) {
|
|
2715
2953
|
printLine(`Warnings: ${sanitizeTerminalText(data.warnings.join('; '))}`)
|
|
2716
2954
|
}
|
|
2717
2955
|
}
|
|
2718
2956
|
|
|
2957
|
+
async function previewAppFromFile() {
|
|
2958
|
+
const filePath = getArg('--file')
|
|
2959
|
+
const inputSchemaPath = getArg('--input-schema')
|
|
2960
|
+
const outputSchemaPath = getArg('--output-schema')
|
|
2961
|
+
const sampleRowPath = getArg('--sample-row')
|
|
2962
|
+
const screenshotPath = getArg('--screenshot')
|
|
2963
|
+
const component = getArg('--component') || undefined
|
|
2964
|
+
const headed = hasArg('--headed')
|
|
2965
|
+
const keepOpen = hasArg('--keep-open')
|
|
2966
|
+
|
|
2967
|
+
if (!filePath || !inputSchemaPath || !outputSchemaPath || !sampleRowPath) {
|
|
2968
|
+
throw new Error('Usage: orizu apps preview --file <path> --input-schema <json-path> --output-schema <json-path> --sample-row <json-path> [--screenshot <png-path>] [--headed] [--keep-open] [--component <name>]')
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
const expandedFilePath = realpathSync(expandHomePath(filePath))
|
|
2972
|
+
const inputJsonSchema = readJsonFile(inputSchemaPath)
|
|
2973
|
+
const outputJsonSchema = readJsonFile(outputSchemaPath)
|
|
2974
|
+
const sampleRow = readJsonFile(sampleRowPath)
|
|
2975
|
+
const expandedScreenshotPath = screenshotPath ? expandHomePath(screenshotPath) : undefined
|
|
2976
|
+
|
|
2977
|
+
const result = await runLocalAppPreview({
|
|
2978
|
+
filePath: expandedFilePath,
|
|
2979
|
+
inputSchema: inputJsonSchema,
|
|
2980
|
+
outputSchema: outputJsonSchema,
|
|
2981
|
+
sampleRow,
|
|
2982
|
+
screenshotPath: expandedScreenshotPath,
|
|
2983
|
+
componentName: component,
|
|
2984
|
+
headed,
|
|
2985
|
+
keepOpen,
|
|
2986
|
+
})
|
|
2987
|
+
|
|
2988
|
+
printLine(`Preview rendered: ${formatTerminalLink(result.url)}`)
|
|
2989
|
+
if (result.screenshotPath) {
|
|
2990
|
+
printLine(`Screenshot: ${sanitizeTerminalText(result.screenshotPath)}`)
|
|
2991
|
+
}
|
|
2992
|
+
if (headed || keepOpen) {
|
|
2993
|
+
printLine('Headed preview is running. Close Chromium or stop the command when you are done.')
|
|
2994
|
+
}
|
|
2995
|
+
if (result.warnings.length > 0) {
|
|
2996
|
+
printLine(`Warnings: ${sanitizeTerminalText(result.warnings.join('; '))}`)
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
|
|
2719
3000
|
async function updateAppFromFile() {
|
|
2720
3001
|
const filePath = getArg('--file')
|
|
2721
3002
|
const inputSchemaPath = getArg('--input-schema')
|
|
@@ -3023,6 +3304,28 @@ interface AppDetailPayload {
|
|
|
3023
3304
|
projectName: string
|
|
3024
3305
|
}
|
|
3025
3306
|
|
|
3307
|
+
interface AppExportPayload {
|
|
3308
|
+
app: {
|
|
3309
|
+
id: string
|
|
3310
|
+
name: string
|
|
3311
|
+
}
|
|
3312
|
+
version: {
|
|
3313
|
+
id: string
|
|
3314
|
+
versionNum: number
|
|
3315
|
+
createdAt?: string
|
|
3316
|
+
code: string
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
|
|
3320
|
+
function defaultAppExportFilename(appName: string, versionNum: number): string {
|
|
3321
|
+
const safeName = appName
|
|
3322
|
+
.trim()
|
|
3323
|
+
.replace(/[^A-Za-z0-9._-]+/g, '_')
|
|
3324
|
+
.replace(/^_+|_+$/g, '')
|
|
3325
|
+
.slice(0, 100)
|
|
3326
|
+
return `${safeName || 'app'}.v${versionNum}.tsx`
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3026
3329
|
async function appDetail() {
|
|
3027
3330
|
const appId = getArg('--app')
|
|
3028
3331
|
const project = getArg('--project')
|
|
@@ -3068,6 +3371,50 @@ async function appDetail() {
|
|
|
3068
3371
|
printLine(` Updated: ${sanitizeTerminalText(detail.updatedAt)}`)
|
|
3069
3372
|
}
|
|
3070
3373
|
|
|
3374
|
+
async function exportAppSource() {
|
|
3375
|
+
const project = getArg('--project')
|
|
3376
|
+
const versionArg = getArg('--version')
|
|
3377
|
+
const outPathArg = getArg('--out')
|
|
3378
|
+
let appId = getArg('--app')
|
|
3379
|
+
|
|
3380
|
+
const versionNum = versionArg && /^[1-9]\d*$/.test(versionArg)
|
|
3381
|
+
? Number.parseInt(versionArg, 10)
|
|
3382
|
+
: undefined
|
|
3383
|
+
|
|
3384
|
+
if (versionArg && versionNum === undefined) {
|
|
3385
|
+
throw new Error('--version must be a positive integer')
|
|
3386
|
+
}
|
|
3387
|
+
|
|
3388
|
+
if (!appId) {
|
|
3389
|
+
const selected = await selectAppIdInteractively(project)
|
|
3390
|
+
appId = selected.appId
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
const query = new URLSearchParams()
|
|
3394
|
+
if (project) {
|
|
3395
|
+
query.set('project', project)
|
|
3396
|
+
}
|
|
3397
|
+
if (versionNum) {
|
|
3398
|
+
query.set('version', String(versionNum))
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
const suffix = query.toString() ? `?${query.toString()}` : ''
|
|
3402
|
+
const response = await authedFetch(`/api/cli/apps/${encodeURIComponent(appId)}/export${suffix}`)
|
|
3403
|
+
if (!response.ok) {
|
|
3404
|
+
throw new Error(`Failed to export app (${response.status}): ${await response.text()}`)
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
const data = await parseJsonResponse<AppExportPayload>(response, 'App export')
|
|
3408
|
+
const filename = outPathArg
|
|
3409
|
+
? expandHomePath(outPathArg)
|
|
3410
|
+
: defaultAppExportFilename(data.app.name, data.version.versionNum)
|
|
3411
|
+
|
|
3412
|
+
writeTextFileEnsuringDir(filename, data.version.code)
|
|
3413
|
+
printLine(
|
|
3414
|
+
`Saved app ${sanitizeTerminalText(data.app.name)} v${data.version.versionNum} source to ${sanitizeTerminalText(filename)}`
|
|
3415
|
+
)
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3071
3418
|
async function listTeamMembers() {
|
|
3072
3419
|
const teamSlug = await resolveTeamSlug(getArg('--team'))
|
|
3073
3420
|
|
|
@@ -3154,7 +3501,8 @@ async function createDatasetFromRows(
|
|
|
3154
3501
|
project: string,
|
|
3155
3502
|
name: string,
|
|
3156
3503
|
sourceType: DatasetUploadSourceType,
|
|
3157
|
-
rows: Array<Record<string, unknown
|
|
3504
|
+
rows: Array<Record<string, unknown>>,
|
|
3505
|
+
readmeMarkdown: string | null = null
|
|
3158
3506
|
): Promise<DatasetUploadResponse> {
|
|
3159
3507
|
const response = await authedFetch('/api/cli/datasets/upload', {
|
|
3160
3508
|
method: 'POST',
|
|
@@ -3166,6 +3514,7 @@ async function createDatasetFromRows(
|
|
|
3166
3514
|
name,
|
|
3167
3515
|
rows,
|
|
3168
3516
|
sourceType,
|
|
3517
|
+
...(readmeMarkdown !== null ? { readmeMarkdown } : {}),
|
|
3169
3518
|
}),
|
|
3170
3519
|
})
|
|
3171
3520
|
|
|
@@ -3180,7 +3529,8 @@ async function createDatasetFromRows(
|
|
|
3180
3529
|
async function uploadJsonlDatasetInChunks(
|
|
3181
3530
|
file: string,
|
|
3182
3531
|
project: string,
|
|
3183
|
-
datasetName: string
|
|
3532
|
+
datasetName: string,
|
|
3533
|
+
readmeMarkdown: string | null = null
|
|
3184
3534
|
) {
|
|
3185
3535
|
let dataset: DatasetUploadResponse['dataset'] | null = null
|
|
3186
3536
|
let totalUploaded = 0
|
|
@@ -3215,7 +3565,7 @@ async function uploadJsonlDatasetInChunks(
|
|
|
3215
3565
|
|
|
3216
3566
|
try {
|
|
3217
3567
|
if (!dataset) {
|
|
3218
|
-
const data = await createDatasetFromRows(project, datasetName, 'jsonl', chunk)
|
|
3568
|
+
const data = await createDatasetFromRows(project, datasetName, 'jsonl', chunk, readmeMarkdown)
|
|
3219
3569
|
dataset = data.dataset
|
|
3220
3570
|
totalUploaded = data.dataset.rowCount
|
|
3221
3571
|
continue
|
|
@@ -3256,22 +3606,24 @@ async function uploadDataset() {
|
|
|
3256
3606
|
const projectArg = getArg('--project')
|
|
3257
3607
|
const fileArg = getArg('--file')
|
|
3258
3608
|
const name = getArg('--name')
|
|
3609
|
+
const usage = 'Usage: orizu datasets upload --file <path> [--project <team/project>] [--name <name>] [--readme-file <README.md> | --readme-text <markdown>]'
|
|
3259
3610
|
|
|
3260
3611
|
if (!fileArg) {
|
|
3261
|
-
throw new Error(
|
|
3612
|
+
throw new Error(usage)
|
|
3262
3613
|
}
|
|
3263
3614
|
|
|
3615
|
+
const readmeMarkdown = readReadmeMarkdownFromArgs(usage)
|
|
3264
3616
|
const file = expandHomePath(fileArg)
|
|
3265
3617
|
const project = await resolveProjectSlug(projectArg)
|
|
3266
3618
|
const datasetName = name || basename(file)
|
|
3267
3619
|
|
|
3268
3620
|
if (extname(file).toLowerCase() === '.jsonl') {
|
|
3269
|
-
await uploadJsonlDatasetInChunks(file, project, datasetName)
|
|
3621
|
+
await uploadJsonlDatasetInChunks(file, project, datasetName, readmeMarkdown)
|
|
3270
3622
|
return
|
|
3271
3623
|
}
|
|
3272
3624
|
|
|
3273
3625
|
const { rows, sourceType } = parseDatasetFile(file)
|
|
3274
|
-
const data = await createDatasetFromRows(project, datasetName, sourceType, rows)
|
|
3626
|
+
const data = await createDatasetFromRows(project, datasetName, sourceType, rows, readmeMarkdown)
|
|
3275
3627
|
|
|
3276
3628
|
printLine(`Uploaded dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}) with ${data.dataset.rowCount} rows.`)
|
|
3277
3629
|
if (data.dataset.url) {
|
|
@@ -3283,23 +3635,29 @@ async function pushDataset() {
|
|
|
3283
3635
|
const projectArg = getArg('--project')
|
|
3284
3636
|
const fileArg = getPositionalArg(2) || getArg('--file')
|
|
3285
3637
|
const name = getArg('--name')
|
|
3638
|
+
const usage = 'Usage: orizu datasets push <rows.csv|rows.json|rows.jsonl> [--project <team/project>] [--name <name>] [--readme-file <README.md> | --readme-text <markdown>] [--json]'
|
|
3286
3639
|
|
|
3287
3640
|
if (!fileArg) {
|
|
3288
|
-
throw new Error(
|
|
3641
|
+
throw new Error(usage)
|
|
3289
3642
|
}
|
|
3290
3643
|
|
|
3644
|
+
const readmeMarkdown = readReadmeMarkdownFromArgs(usage)
|
|
3291
3645
|
const file = expandHomePath(fileArg)
|
|
3292
3646
|
const project = await resolveProjectSlug(projectArg)
|
|
3293
3647
|
const datasetName = name || basename(file)
|
|
3294
3648
|
const { rows, sourceType } = parseDatasetFile(file)
|
|
3295
|
-
const data = await createDatasetFromRows(project, datasetName, sourceType, rows)
|
|
3649
|
+
const data = await createDatasetFromRows(project, datasetName, sourceType, rows, readmeMarkdown)
|
|
3296
3650
|
|
|
3297
3651
|
if (hasJsonFlag()) {
|
|
3298
|
-
|
|
3652
|
+
const payload: Record<string, unknown> = {
|
|
3299
3653
|
dataset_id: data.dataset.id,
|
|
3300
3654
|
name: data.dataset.name,
|
|
3301
3655
|
row_count: data.dataset.rowCount,
|
|
3302
|
-
}
|
|
3656
|
+
}
|
|
3657
|
+
if (data.readmeVersion?.id) {
|
|
3658
|
+
payload.readme_version_id = data.readmeVersion.id
|
|
3659
|
+
}
|
|
3660
|
+
printJson(payload)
|
|
3303
3661
|
return
|
|
3304
3662
|
}
|
|
3305
3663
|
|
|
@@ -3309,6 +3667,55 @@ async function pushDataset() {
|
|
|
3309
3667
|
}
|
|
3310
3668
|
}
|
|
3311
3669
|
|
|
3670
|
+
async function setDatasetReadme() {
|
|
3671
|
+
const datasetId = getPositionalArg(3) || getArg('--dataset')
|
|
3672
|
+
const project = getArg('--project')
|
|
3673
|
+
const usage = 'Usage: orizu datasets readme set <datasetId|dataset-name> [--project <team/project>] (--readme-file <README.md> | --readme-text <markdown>) [--json]'
|
|
3674
|
+
|
|
3675
|
+
if (!datasetId) {
|
|
3676
|
+
throw new Error(usage)
|
|
3677
|
+
}
|
|
3678
|
+
|
|
3679
|
+
const readmeMarkdown = readReadmeMarkdownFromArgs(usage)
|
|
3680
|
+
if (readmeMarkdown === null) {
|
|
3681
|
+
throw new Error(usage)
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
const resolvedDatasetId = await resolveDatasetIdForProject(datasetId, project)
|
|
3685
|
+
const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(resolvedDatasetId)}/readme`, {
|
|
3686
|
+
method: 'POST',
|
|
3687
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3688
|
+
body: JSON.stringify({ markdown: readmeMarkdown }),
|
|
3689
|
+
})
|
|
3690
|
+
|
|
3691
|
+
if (!response.ok) {
|
|
3692
|
+
throw new Error(`Failed to save dataset README: ${await response.text()}`)
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
const data = await parseJsonResponse<{
|
|
3696
|
+
version: {
|
|
3697
|
+
id: string
|
|
3698
|
+
dataset_id: string
|
|
3699
|
+
version_num: number
|
|
3700
|
+
created_at: string
|
|
3701
|
+
}
|
|
3702
|
+
}>(response, 'Dataset README save')
|
|
3703
|
+
|
|
3704
|
+
if (hasJsonFlag()) {
|
|
3705
|
+
printJson({
|
|
3706
|
+
dataset_id: data.version.dataset_id,
|
|
3707
|
+
readme_version_id: data.version.id,
|
|
3708
|
+
readme_version_num: data.version.version_num,
|
|
3709
|
+
})
|
|
3710
|
+
return
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
printLine(
|
|
3714
|
+
`Saved README v${data.version.version_num} for dataset ` +
|
|
3715
|
+
`${sanitizeTerminalText(data.version.dataset_id)} (${sanitizeTerminalText(data.version.id)}).`
|
|
3716
|
+
)
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3312
3719
|
function getDatasetReferenceInput(): string | null {
|
|
3313
3720
|
const fromFlag = getArg('--dataset')
|
|
3314
3721
|
if (fromFlag) {
|
|
@@ -4180,6 +4587,11 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4180
4587
|
return
|
|
4181
4588
|
}
|
|
4182
4589
|
|
|
4590
|
+
if (command === 'scorers' && subcommand === 'exec') {
|
|
4591
|
+
await execScorer()
|
|
4592
|
+
return
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4183
4595
|
if (command === 'runners' && subcommand === 'push') {
|
|
4184
4596
|
await pushRunnerArtifact('runner')
|
|
4185
4597
|
return
|
|
@@ -4244,6 +4656,11 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4244
4656
|
return
|
|
4245
4657
|
}
|
|
4246
4658
|
|
|
4659
|
+
if (command === 'apps' && subcommand === 'preview') {
|
|
4660
|
+
await previewAppFromFile()
|
|
4661
|
+
return
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4247
4664
|
if (command === 'apps' && subcommand === 'update') {
|
|
4248
4665
|
await updateAppFromFile()
|
|
4249
4666
|
return
|
|
@@ -4259,6 +4676,11 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4259
4676
|
return
|
|
4260
4677
|
}
|
|
4261
4678
|
|
|
4679
|
+
if (command === 'apps' && subcommand === 'export') {
|
|
4680
|
+
await exportAppSource()
|
|
4681
|
+
return
|
|
4682
|
+
}
|
|
4683
|
+
|
|
4262
4684
|
if (command === 'tasks' && subcommand === 'list') {
|
|
4263
4685
|
await listTasks()
|
|
4264
4686
|
return
|
|
@@ -4310,6 +4732,11 @@ export async function main(rawArgs = process.argv.slice(2)) {
|
|
|
4310
4732
|
}
|
|
4311
4733
|
|
|
4312
4734
|
const datasetsAction = cliArgs[2]
|
|
4735
|
+
if (command === 'datasets' && subcommand === 'readme' && datasetsAction === 'set') {
|
|
4736
|
+
await setDatasetReadme()
|
|
4737
|
+
return
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4313
4740
|
if (command === 'datasets' && subcommand === 'versions' && datasetsAction === 'create') {
|
|
4314
4741
|
await createDatasetVersion()
|
|
4315
4742
|
return
|