@evolvingmachines/evolve 0.0.64 → 0.0.65

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/spec/openapi.yaml CHANGED
@@ -483,11 +483,18 @@ paths:
483
483
  tags: [jobs]
484
484
  operationId: listJobs
485
485
  summary: List jobs
486
- description: Newest first. Every filter is server-side.
486
+ description: >
487
+ Newest first. Every filter is server-side. A task quality check is a
488
+ job in Harbor (their `harbor check` runs its wrapper tasks as a single
489
+ Harbor job, analyze/checker.py:1-8, under the same `jobs/` directory
490
+ `harbor run` writes to), so `kind` lets one listing hold both:
491
+ `kind=all` merges jobs and checks newest first under the one cursor,
492
+ each row told apart by `JobListItem.kind`.
487
493
  parameters:
488
494
  - $ref: '#/components/parameters/Limit'
489
495
  - $ref: '#/components/parameters/Cursor'
490
496
  - $ref: '#/components/parameters/ListScope'
497
+ - $ref: '#/components/parameters/JobListKind'
491
498
  - name: status
492
499
  in: query
493
500
  description: Filter by job status (repeatable).
@@ -1809,9 +1816,10 @@ paths:
1809
1816
  stay stored. The body is optional — `{}` or absent means the
1810
1817
  defaults (openrouter/deepseek/deepseek-v4.1-flash at its per-model effort,
1811
1818
  the platform's default analyze rubric). CANCELLED trials are never analyzed. Which trials
1812
- and how wide are Harbor's own options on the body — `passing` /
1813
- `failing` (the reward filter), `n_trials` (the cap, after the
1814
- filter), `n_concurrent` (the width, beneath the organization's
1819
+ and how wide are Harbor's own options on the body — `trial_ids` (the
1820
+ named trials, before the filter and the cap), `passing` / `failing`
1821
+ (the reward filter), `n_trials` (the cap, after the filter),
1822
+ `n_concurrent` (the width, beneath the organization's
1815
1823
  `max_concurrent_analyses`).
1816
1824
 
1817
1825
  An analyzer run that completes without a valid `analysis.json` is
@@ -1830,9 +1838,12 @@ paths:
1830
1838
  the same way under `invalid_rubric`, PostgreSQL's jsonb ceiling
1831
1839
  named — an off-lineup `sandbox_provider`, an off-vocabulary
1832
1840
  `reasoning_effort`, an out-of-range `n_concurrent`, `passing` together
1833
- with `failing`, an invalid `n_trials` — in that order) → 409
1841
+ with `failing`, an invalid `n_trials`, a malformed `trial_ids` — in
1842
+ that order) → 400 `invalid_input` for a `trial_ids` entry that is not
1843
+ a trial of this job (`details.unknown_trial_ids`) → 409
1834
1844
  `analysis_already_running` → 409 `no_analyzable_trials` (no analyzable
1835
- trial at all, or none on the side of the reward filter) → 202.
1845
+ trial at all, none on the side of the reward filter, or none of the
1846
+ named trials) → 202.
1836
1847
  parameters:
1837
1848
  - $ref: '#/components/parameters/JobId'
1838
1849
  requestBody:
@@ -1858,9 +1869,10 @@ paths:
1858
1869
  description: >
1859
1870
  `job_not_terminal`, `analysis_already_running` (one wave at a
1860
1871
  time; retry after the running wave settles), or
1861
- `no_analyzable_trials` (every trial CANCELLED, or no trial on
1862
- the side of the `passing` / `failing` filter — Harbor's "No
1863
- passing trial directories found", analyzer.py:192-200).
1872
+ `no_analyzable_trials` (every trial CANCELLED, no trial on the
1873
+ side of the `passing` / `failing` filter, or none of the named
1874
+ `trial_ids` — Harbor's "No passing trial directories found",
1875
+ analyzer.py:192-200).
1864
1876
  content:
1865
1877
  application/json:
1866
1878
  schema:
@@ -4974,6 +4986,44 @@ paths:
4974
4986
  '500':
4975
4987
  $ref: '#/components/responses/InternalError'
4976
4988
 
4989
+ /api/analyses/defaults:
4990
+ get:
4991
+ tags: [analyses]
4992
+ operationId: getAnalyzeDefaults
4993
+ summary: The defaults an analysis runs under when its config names nothing
4994
+ description: |
4995
+ The resolved policy an empty `AnalyzeConfigInput` falls back to — the
4996
+ five knobs every analysis that names none is stamped with:
4997
+ `model_name`, `rubric` (the platform's analyze rubric, the seven
4998
+ criteria `AnalyzeConfigInput` lists), `prompt` (the built-in analyze
4999
+ body, as the TEMPLATE a caller's own `prompt` replaces — with its
5000
+ `{trial_path}`, `{task_section}` and `{criteria_guidance}` slots
5001
+ unrendered; the output section Harbor appends is not part of it),
5002
+ `reasoning_effort` (the default model's per-model effort) and
5003
+ `sandbox_provider` (the fleet default). Read them to see what a
5004
+ bare `evolve analyze` runs under, or to start an edited rubric or
5005
+ prompt from the platform's own. `model_name` and `rubric` sent
5006
+ back resolve as if nothing was sent; `prompt`, `reasoning_effort`
5007
+ and `sandbox_provider` sent back are stored as named, so the
5008
+ analysis echoes the prompt text and keeps that effort and provider
5009
+ even when the fleet default later changes. Harbor has no such verb:
5010
+ its defaults are files on disk (analyze/prompts/analyze.txt and its
5011
+ default analyze rubric), which a hosted caller cannot open — the
5012
+ hosted reading of the same files.
5013
+ responses:
5014
+ '200':
5015
+ description: The resolved defaults.
5016
+ content:
5017
+ application/json:
5018
+ schema:
5019
+ $ref: '#/components/schemas/AnalyzeDefaults'
5020
+ '401':
5021
+ $ref: '#/components/responses/Unauthorized'
5022
+ '429':
5023
+ $ref: '#/components/responses/TooManyRequests'
5024
+ '500':
5025
+ $ref: '#/components/responses/InternalError'
5026
+
4977
5027
  /api/analyses/{analysisId}/filesystem:
4978
5028
  get:
4979
5029
  tags: [analyses]
@@ -10508,11 +10558,49 @@ components:
10508
10558
  address, and `org` the organization's — and its `liveCount` is
10509
10559
  informational under both: stopping stays creator-or-admin, so nothing
10510
10560
  it counts that is not yours is yours to
10511
- stop.
10561
+ stop. That feed also takes `org` (slug or id) exactly as
10562
+ `GET /api/jobs?org=` does — `GET /api/traces?org=` lists ONE
10563
+ organization's runs of every kind; membership is required, a
10564
+ stranger's org answers `org_not_found`, and `scope` with `org` is
10565
+ refused (`invalid_input`), since each names a selection; so is
10566
+ `admin=true` with `org`.
10512
10567
  schema:
10513
10568
  type: string
10514
10569
  enum: [my, shared, org]
10515
10570
  default: my
10571
+ JobListKind:
10572
+ name: kind
10573
+ in: query
10574
+ description: >
10575
+ Which run kinds the page lists: `job` — jobs (regrades included),
10576
+ the default and exactly what an absent parameter always listed;
10577
+ `check` — task quality checks only; `all` — jobs and checks merged
10578
+ newest first under the one cursor, each row a `JobListItem` told
10579
+ apart by its `kind`. In Harbor a check IS a job: `harbor check` runs
10580
+ its wrapper tasks as a single Harbor job (analyze/checker.py:1-8),
10581
+ takes `--job-name` (cli/analyze.py:138-140) and writes under the
10582
+ same `jobs/` directory `harbor run` uses (`--jobs-dir`, default
10583
+ `jobs`, cli/analyze.py:141-143 and cli/jobs.py:442-450; the job dir
10584
+ is `jobs_dir / job_name`, job.py:634-635). Recorded deviation:
10585
+ Harbor lists runs and checks as the folders of that one directory
10586
+ with no filter; the hosted list needs one so `job list` scripts keep
10587
+ their meaning, so `kind` exists here and defaults to `job`. The same
10588
+ `scope` words and `org` apply to both kinds, and a check is listed
10589
+ under the rule that lets `GET /api/checks/{checkId}` read it. Every
10590
+ other filter narrows a check by the same words: `status` by the
10591
+ check's own ladder (`QUEUED` and `RUNNING` match `queued` and
10592
+ `running`; `COMPLETED` matches a `completed` check none of whose task
10593
+ checks was stopped; `CANCELLED` matches a `completed` check with a
10594
+ stopped task check, the row the dashboard reads Stopped; `CANCELLING`
10595
+ and `FAILED` match no check), `model` and `sandbox_provider` by the
10596
+ checker's, `dataset` by the check's dataset source (every version of
10597
+ that name), `search` by the check's name and dataset source; `agent`
10598
+ names an arm, so it lists no check; `is_regrade=true` lists no check
10599
+ and `is_regrade=false` keeps them (a check is not a regrade).
10600
+ schema:
10601
+ type: string
10602
+ enum: [job, check, all]
10603
+ default: job
10516
10604
  IdempotencyKey:
10517
10605
  name: Idempotency-Key
10518
10606
  in: header
@@ -12300,6 +12388,12 @@ components:
12300
12388
  (`-l/--n-trials`) — their cli/analyze.py:278-290. Every one is
12301
12389
  optional; all omitted is today's behaviour: every analyzable trial,
12302
12390
  as wide as the organization's `max_concurrent_analyses` allows.
12391
+ `trial_ids` is Harbor's other way to choose: `harbor analyze <trial
12392
+ directory>` — their PATH is "a trial directory or a job directory of
12393
+ trials" (cli/analyze.py:242-245), and one trial directory is analyzed
12394
+ as itself (analyzer.py:174-181 `_resolve_trial_dirs`) — hosted, the
12395
+ trials of this job named by id. Only `POST /api/jobs/{jobId}/analyze`
12396
+ takes it; on `JobCreate.analyze` the trials do not exist yet.
12303
12397
 
12304
12398
  Harbor's other analyze options, and why they are not here:
12305
12399
  `-a/--agent` — the analyzer harness is claude-code, fixed (the
@@ -12479,6 +12573,29 @@ components:
12479
12573
  spent as trials finish, so settle order decides. Not an
12480
12574
  integer of at least 1 is refused `invalid_input` naming
12481
12575
  `analyze.n_trials`.
12576
+ trial_ids:
12577
+ type: array
12578
+ minItems: 1
12579
+ uniqueItems: true
12580
+ items:
12581
+ type: string
12582
+ minLength: 1
12583
+ description: >
12584
+ Analyze only these trials of the job — Harbor's `harbor analyze
12585
+ <trial directory>` for one trial (their cli/analyze.py:242-245;
12586
+ analyzer.py:174-181), given as ids here; combinable with
12587
+ `passing`/`failing` (a listed trial on the other side of the
12588
+ filter is skipped) and applied before `n_trials` (Harbor's
12589
+ one-trial path skips its filter and cap, analyzer.py:180-181
12590
+ before :189-191; hosted, both apply to the named trials too).
12591
+ An id that is not a trial of this job is refused `invalid_input`
12592
+ naming `analyze.trial_ids`, with the unknown ids named in the
12593
+ message and in `details.unknown_trial_ids`; a list that leaves
12594
+ nothing analyzable is the existing 409 `no_analyzable_trials`. An
12595
+ empty list, a duplicate, an empty string or a non-string is
12596
+ refused `invalid_input` naming `analyze.trial_ids`. On
12597
+ `JobCreate.analyze` (the embedded trigger) it is refused
12598
+ `invalid_input` — trials do not exist yet.
12482
12599
 
12483
12600
  AnalyzeConfig:
12484
12601
  type: object
@@ -12491,7 +12608,7 @@ components:
12491
12608
  (`Trial.analysis.model_name` / `.rubric` / `.prompt` /
12492
12609
  `.reasoning_effort`), which a later manual re-analysis may have
12493
12610
  changed.
12494
- required: [model_name, rubric, prompt, reasoning_effort, sandbox_provider, n_concurrent, passing, failing, n_trials]
12611
+ required: [model_name, rubric, prompt, reasoning_effort, sandbox_provider, n_concurrent, passing, failing, n_trials, trial_ids]
12495
12612
  properties:
12496
12613
  model_name:
12497
12614
  type: string
@@ -12544,6 +12661,15 @@ components:
12544
12661
  description: >
12545
12662
  The trial cap as stored (`AnalyzeConfigInput.n_trials`); null =
12546
12663
  no cap.
12664
+ trial_ids:
12665
+ type: [array, 'null']
12666
+ items:
12667
+ type: string
12668
+ description: >
12669
+ Always null on the job body today: the stored policy is the
12670
+ create-time one (`JobCreate.analyze`), which refuses `trial_ids`;
12671
+ the trials a manual wave names are the analysis rows it enqueues,
12672
+ never a field of the job.
12547
12673
 
12548
12674
  # -------------------------------------------------------------------------
12549
12675
  # Job — result side
@@ -12829,6 +12955,7 @@ components:
12829
12955
  not others. The create verb answers with JobCreated, which is this
12830
12956
  shape plus one aliased id and nothing else.
12831
12957
  required:
12958
+ - kind
12832
12959
  - id
12833
12960
  - job_name
12834
12961
  - status
@@ -12857,12 +12984,19 @@ components:
12857
12984
  - failure
12858
12985
  - source_jobs
12859
12986
  - is_regrade
12987
+ - viewer
12860
12988
  - upload
12861
12989
  - idempotent_replay
12862
12990
  - started_at
12863
12991
  - updated_at
12864
12992
  - finished_at
12865
12993
  properties:
12994
+ kind:
12995
+ type: string
12996
+ enum: [job]
12997
+ description: >
12998
+ The row's kind on the jobs list (`JobListItem`): always `job` on
12999
+ a Job body, a regrade included; a check row says `check`.
12866
13000
  id:
12867
13001
  type: string
12868
13002
  format: uuid
@@ -13010,6 +13144,19 @@ components:
13010
13144
  is_regrade:
13011
13145
  type: boolean
13012
13146
  description: 'Derived: any source_jobs entry with action "regrade".'
13147
+ viewer:
13148
+ type: [string, 'null']
13149
+ enum: [creator, member, shared, link, null]
13150
+ description: >
13151
+ The caller's relation to the job on a read: `creator` made it,
13152
+ `member` belongs to its organization, `shared` reads it through
13153
+ an email share, `link` through its unlisted link. Null on
13154
+ responses that echo a job the caller just acted on (create,
13155
+ analyze, cancel, resume, retry, regrade), where the
13156
+ caller is the creator or a member by construction, and on list
13157
+ rows (`GET /api/jobs`), which are batched; read one job to learn
13158
+ the relation. Acting verbs are open to `creator` and `member`
13159
+ only.
13013
13160
  upload:
13014
13161
  oneOf:
13015
13162
  - $ref: '#/components/schemas/UploadProvenance'
@@ -13786,15 +13933,134 @@ components:
13786
13933
  format: uuid
13787
13934
  description: Alias of `id`, identical value. Create responses only.
13788
13935
 
13936
+ JobListItem:
13937
+ description: >
13938
+ One row of the jobs list, told apart by `kind`: a `Job` (`kind:
13939
+ job`), or a `CheckRow` (`kind: check`) when the listing asked for
13940
+ `kind=check` or `kind=all`. Under the default `kind=job` every row
13941
+ is a Job.
13942
+ oneOf:
13943
+ - $ref: '#/components/schemas/Job'
13944
+ - $ref: '#/components/schemas/CheckRow'
13945
+ discriminator:
13946
+ propertyName: kind
13947
+ mapping:
13948
+ job: '#/components/schemas/Job'
13949
+ check: '#/components/schemas/CheckRow'
13950
+
13951
+ CheckRow:
13952
+ type: object
13953
+ description: >
13954
+ A task quality check as one row of the jobs list (`GET /api/jobs`
13955
+ with `kind=check` or `kind=all`): the Check body's own facts without
13956
+ its per-task results, rubric and prompt (`GET /api/checks/{checkId}`
13957
+ serves those), plus the tally the list needs. In Harbor a check IS a
13958
+ job — its wrapper tasks run as one Harbor job under
13959
+ `jobs/<job-name>` (analyze/checker.py:1-8) — so it lists beside
13960
+ jobs here. The row is not a Job: a check has no arms, attempts,
13961
+ caps, retry policy, trials or upload provenance, so those fields are
13962
+ absent rather than faked. Each field says what the Jobs page reads
13963
+ it as.
13964
+ required:
13965
+ - kind
13966
+ - id
13967
+ - name
13968
+ - status
13969
+ - source
13970
+ - model_name
13971
+ - reasoning_effort
13972
+ - sandbox_provider
13973
+ - org
13974
+ - visibility
13975
+ - tasks
13976
+ - cost_usd
13977
+ - created_at
13978
+ - finished_at
13979
+ properties:
13980
+ kind:
13981
+ type: string
13982
+ enum: [check]
13983
+ description: Tells the row from a Job on `JobListItem`.
13984
+ id:
13985
+ type: string
13986
+ format: uuid
13987
+ description: The check's id — the row opens at `GET /api/checks/{checkId}`.
13988
+ name:
13989
+ type: string
13990
+ description: Check.name, Harbor's `--job-name` (the caller's, or the accept stamp); the row's JOB cell.
13991
+ status:
13992
+ type: string
13993
+ enum: [queued, running, completed]
13994
+ description: Check.status, derived from its tasks; the row's STATUS cell. The list's `status` words map onto it as the `kind` parameter says (a `completed` check with a stopped task check answers `CANCELLED`, not `COMPLETED`).
13995
+ source:
13996
+ $ref: '#/components/schemas/CheckSource'
13997
+ description: What was checked; the row's DATASETS cell (the dataset form's `name@version`; an archive shows as an archive with its sha256).
13998
+ model_name:
13999
+ type: string
14000
+ description: The checker's model; the row's AGENTS cell, shown like an arm with its effort under it.
14001
+ reasoning_effort:
14002
+ type: string
14003
+ description: The effort every task's checker ran at, as Check.reasoning_effort.
14004
+ sandbox_provider:
14005
+ allOf:
14006
+ - $ref: '#/components/schemas/SandboxProvider'
14007
+ description: Where the checker ran, as Check.sandbox_provider.
14008
+ org:
14009
+ type: string
14010
+ description: The owning organization's slug (every check has one), like Job.org.
14011
+ visibility:
14012
+ $ref: '#/components/schemas/JobVisibility'
14013
+ description: As Check.visibility — `PRIVATE`, or `LINK` while the check's unlisted link is on.
14014
+ tasks:
14015
+ $ref: '#/components/schemas/CheckTaskTally'
14016
+ description: How many task checks, and how they break down; the row's TRIALS cell reads done (completed, failed and stopped) of total.
14017
+ cost_usd:
14018
+ type: [number, 'null']
14019
+ description: Check.cost_usd, the sum of the measured task costs (null when none was measured); the row's COST cell.
14020
+ created_at:
14021
+ type: string
14022
+ format: date-time
14023
+ description: The accept instant; the list orders it with the jobs' `started_at` (newest first, `id` as the tiebreak); the row's CREATED cell.
14024
+ finished_at:
14025
+ type: [string, 'null']
14026
+ format: date-time
14027
+ description: When the last task settled; null until every task has.
14028
+
14029
+ CheckTaskTally:
14030
+ type: object
14031
+ description: >
14032
+ The "how many" shape of a check's task checks — a total plus a
14033
+ histogram over the task check statuses, zeros included
14034
+ (TrialStatusTally's twin on the check's own ladder). A task check
14035
+ the user stopped is stored `failed` with the stop phase
14036
+ (`failure.phase` `stopped`, or `job_cancelled`); the tally counts
14037
+ it under `stopped`, never `failed`, so a stop never reads as a
14038
+ failure.
14039
+ required: [total, byStatus]
14040
+ properties:
14041
+ total:
14042
+ type: integer
14043
+ minimum: 0
14044
+ byStatus:
14045
+ type: object
14046
+ description: One integer per TaskCheck status plus `stopped`, zeros included.
14047
+ required: [queued, running, completed, failed, stopped]
14048
+ properties:
14049
+ queued: { type: integer, minimum: 0 }
14050
+ running: { type: integer, minimum: 0 }
14051
+ completed: { type: integer, minimum: 0 }
14052
+ failed: { type: integer, minimum: 0 }
14053
+ stopped: { type: integer, minimum: 0 }
14054
+
13789
14055
  JobPage:
13790
14056
  type: object
13791
- description: Cursor page of jobs (envelope keys frozen verbatim).
14057
+ description: Cursor page of jobs (envelope keys frozen verbatim). Rows are `JobListItem`s — Jobs, and CheckRows when `kind` asked for them.
13792
14058
  required: [items, nextCursor, hasMore]
13793
14059
  properties:
13794
14060
  items:
13795
14061
  type: array
13796
14062
  items:
13797
- $ref: '#/components/schemas/Job'
14063
+ $ref: '#/components/schemas/JobListItem'
13798
14064
  nextCursor:
13799
14065
  type: [string, 'null']
13800
14066
  description: Pass back as `?cursor=`; null means no next page.
@@ -15078,6 +15344,33 @@ components:
15078
15344
  format: date-time
15079
15345
  description: When the last task settled; null until every task has.
15080
15346
 
15347
+ AnalyzeDefaults:
15348
+ type: object
15349
+ description: >
15350
+ The policy an empty `AnalyzeConfigInput` resolves to (GET
15351
+ /api/analyses/defaults) — each key the same value `AnalyzeConfig`
15352
+ echoes for a job created with `analyze: {}`, except `prompt`, which
15353
+ `AnalyzeConfig` serves as null (the built-in body) and this serves as
15354
+ that body's template text.
15355
+ required: [model_name, rubric, prompt, reasoning_effort, sandbox_provider]
15356
+ properties:
15357
+ model_name:
15358
+ type: string
15359
+ rubric:
15360
+ $ref: '#/components/schemas/Rubric'
15361
+ prompt:
15362
+ type: string
15363
+ description: >
15364
+ The built-in analyze prompt template, unrendered — pass it as
15365
+ `AnalyzeConfigInput.prompt` to run the default body explicitly,
15366
+ or edit it from here.
15367
+ reasoning_effort:
15368
+ type: string
15369
+ description: The effort the default model runs at when the config names none.
15370
+ sandbox_provider:
15371
+ allOf:
15372
+ - $ref: '#/components/schemas/SandboxProvider'
15373
+
15081
15374
  CheckDefaults:
15082
15375
  type: object
15083
15376
  description: >
@@ -18281,6 +18574,13 @@ components:
18281
18574
  description: >
18282
18575
  Most ids (trials and trace analyses) one stop request may
18283
18576
  name (StopRequest mirrors it as maxItems).
18577
+ max_run_ids:
18578
+ type: integer
18579
+ description: >
18580
+ Most ids the ids form of `POST /api/traces/stop` (the
18581
+ dashboard's stop verb over every live run kind, not a path
18582
+ of this contract) may name in one request; a client
18583
+ stopping more sends several.
18284
18584
  pagination:
18285
18585
  type: object
18286
18586
  properties: