@archmax-ai/harness 1.0.1 → 1.1.0

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.
Files changed (48) hide show
  1. package/README.md +11 -6
  2. package/dist/assembly/compose.js +3 -1
  3. package/dist/assembly/compose.js.map +1 -1
  4. package/dist/authoring-skill/archmax-harness/SKILL.md +5 -2
  5. package/dist/authoring-skill/archmax-harness/references/backend-integration.md +25 -13
  6. package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +36 -6
  7. package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +3 -0
  8. package/dist/core/attachments.d.ts +2 -0
  9. package/dist/core/attachments.js +2 -1
  10. package/dist/core/attachments.js.map +1 -1
  11. package/dist/core/file-operations.d.ts +6 -0
  12. package/dist/core/file-operations.js +29 -0
  13. package/dist/core/file-operations.js.map +1 -1
  14. package/dist/index.d.ts +5 -1
  15. package/dist/index.js +4 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/machine/signature-pattern.d.ts +24 -0
  18. package/dist/machine/signature-pattern.js +67 -0
  19. package/dist/machine/signature-pattern.js.map +1 -0
  20. package/dist/machine/signature.d.ts +137 -35
  21. package/dist/machine/signature.js +476 -25
  22. package/dist/machine/signature.js.map +1 -1
  23. package/dist/machine/spec-schema.d.ts +202 -1
  24. package/dist/machine/spec-schema.js +143 -4
  25. package/dist/machine/spec-schema.js.map +1 -1
  26. package/dist/public/spec.d.ts +5 -1
  27. package/dist/public/spec.js +4 -0
  28. package/dist/public/spec.js.map +1 -1
  29. package/dist/workflow/control-tools.js +3 -1
  30. package/dist/workflow/control-tools.js.map +1 -1
  31. package/dist/workflow/file-values.d.ts +4 -1
  32. package/dist/workflow/file-values.js +2 -0
  33. package/dist/workflow/file-values.js.map +1 -1
  34. package/dist/workflow/middleware.d.ts +2 -0
  35. package/dist/workflow/middleware.js +1 -0
  36. package/dist/workflow/middleware.js.map +1 -1
  37. package/dist/workflow/render-prompt.js +7 -2
  38. package/dist/workflow/render-prompt.js.map +1 -1
  39. package/dist/workflow/signature-checks.d.ts +8 -3
  40. package/dist/workflow/signature-checks.js +17 -4
  41. package/dist/workflow/signature-checks.js.map +1 -1
  42. package/dist/workflow/sub-workflow.js +4 -1
  43. package/dist/workflow/sub-workflow.js.map +1 -1
  44. package/package.json +2 -1
  45. package/skills/archmax-harness/SKILL.md +5 -2
  46. package/skills/archmax-harness/references/backend-integration.md +25 -13
  47. package/skills/archmax-harness/references/workflow-schema.md +36 -6
  48. package/skills/archmax-harness/references/workflow-yaml.md +3 -0
@@ -82,7 +82,7 @@ From `@archmax-ai/harness` (`src/index.ts`):
82
82
  | `workflowStateSchema`, `workflowPaths`, `sessionPaths`, `runArtifactPaths` | schema/fn | State schema + path helpers |
83
83
  | `runTests`, `RunTestsOptions`, `CaseResult` | fn/type | Run a workflow's cases — [against your own agent](#cases-against-your-agent) |
84
84
  | `toolsFromMap`, `AgentToolDescriptor`, `ToolContext`, `ToolPaths`, `PathAccess`, `ToolPathsError` | fn/type/class | Host tools: a `name → descriptor` map, each descriptor's declared `paths` and a handler handed the turn's workspace — [host tools](#host-tools) |
85
- | `SIGNATURE_TYPES`, `normalizeSignature`, `signatureForTrigger`, `signatureJsonSchema`, `signatureValueIssues` | const/fn | A trigger's typed signature as JSON Schema and its conformance rule — [exposing a workflow](#exposing-a-workflow-to-outside-callers); also on `@archmax-ai/harness/spec` |
85
+ | `SIGNATURE_TYPES`, `SIGNATURE_FORMATS`, `SIGNATURE_CONTENTS`, `normalizeSignature`, `signatureForTrigger`, `signatureJsonSchema`, `signatureValueIssues` | const/fn | A trigger's typed signature, rules included, as JSON Schema and its conformance rule — [exposing a workflow](#exposing-a-workflow-to-outside-callers); also on `@archmax-ai/harness/spec` |
86
86
 
87
87
  ## createAgent options
88
88
 
@@ -399,12 +399,22 @@ const outcome = await agent.workflow!.send(sessionId, { message: "Refund the ord
399
399
  - `signatureJsonSchema(entries)` → `{ type: "object", properties, required }`:
400
400
  one property per entry in declaration order, every name required,
401
401
  `date`/`date-time`/`file` as `{ type: "string", format }`, an untyped entry as `{}`,
402
- an entry's `description` carried over. It adds no `additionalProperties`; set
403
- it for your own ingress.
404
- - `signatureValueIssues(entries, values)` → one issue per missing name and per
405
- non-conforming value; `[]` means the turn boundary will not refuse the map for
406
- its signature. It **never coerces**: a form that collects text converts
407
- `"4"` to `4` before it validates or seeds.
402
+ an entry's `description` carried over. Rules map to their JSON Schema keywords:
403
+ `format: email` → `format: "email"`, `format: url` → `format: "uri"` plus
404
+ `pattern: "^https?://"`, `format: phone` → the E.164 `pattern`; `pattern`,
405
+ `minLength`/`maxLength`, `enum`, numeric `minimum`/`maximum` and
406
+ `minItems`/`maxItems` as themselves; `content` → `contentMediaType`. Date
407
+ bounds, `accept` and `maxSize` are not mapped (the runtime still enforces
408
+ them). It adds no `additionalProperties`; set it for your own ingress.
409
+ - `signatureValueIssues(entries, values, options?)` → one issue per missing name
410
+ and per non-conforming value; `[]` means the turn boundary will not refuse the
411
+ map for its signature. A value breaking a rule is an `invalid` issue carrying
412
+ `rule` (one per entry, the first rule broken), so code that filters
413
+ `kind === "invalid"` enforces rules unchanged. `options.now` pins the clock
414
+ for `today`/`now` (tests, a host's own clock). It is synchronous, pure and
415
+ browser-safe, and a `pattern` runs in RE2, so it is safe in a request path on
416
+ input from anyone. It **never coerces or trims**: a form that collects text
417
+ converts `"4"` to `4` before it validates or seeds.
408
418
  - A trigger's `description` is written for the caller. Use it as the MCP tool
409
419
  or operation description. The session's own model never sees it.
410
420
  - **A `file` entry** (`format: "file"` in the schema) takes a workspace path. To
@@ -417,13 +427,15 @@ const outcome = await agent.workflow!.send(sessionId, { message: "Refund the ord
417
427
  `InvalidTurnFileError`, before anything is written, for a bad variable or file
418
428
  name, a variable also given in `variables`, a session parked at a human state, or
419
429
  bytes the store cannot hold exactly (a non-text file needs a store with
420
- `uploadFiles`). `signatureValueIssues` checks only a `file` value's shape, so a
421
- start form validates the path the upload will produce, or skips the entry and
422
- lets `files` supply it.
430
+ `uploadFiles`). `signatureValueIssues` checks only a `file` value's shape and its
431
+ `accept` extensions, so a start form validates the path the upload will
432
+ produce, or skips the entry and lets `files` supply it; `maxSize` is checked by
433
+ the runtime at the turn boundary, against the placed file.
423
434
  - A host that reads specs itself must read `requires`/`returns` through
424
- `normalizeSignature` (both spellings → `{ name, type?, description? }[]`),
425
- never as `string[]`: an entry may be an object. Hosts must be on the release
426
- that introduced typed entries before any workspace they read uses them.
435
+ `normalizeSignature` (both spellings → `{ name, type?, description?, …rules }[]`,
436
+ `maxSize` in bytes, `today`/`now` kept symbolic), never as `string[]`: an entry
437
+ may be an object. Hosts must be on the release that introduced typed entries
438
+ (and, for rules, 1.1.0) before any workspace they read uses them.
427
439
 
428
440
  ## Lifecycle events
429
441
 
@@ -606,7 +606,8 @@ states:
606
606
  description: Enrich one order and say whether it is late. # for callers only
607
607
  requires: # a firing must supply these to start
608
608
  - order_id # bare name = untyped
609
- - { name: due, type: date, description: The day the order is due. }
609
+ - { name: due, type: date, minimum: today, description: The day the order is due. }
610
+ - { name: priority, type: string, enum: [low, normal, high] } # a rule
610
611
  returns: # the run guarantees these when it completes
611
612
  - enrichment_file
612
613
  - { name: delayed, type: boolean }
@@ -635,10 +636,11 @@ states:
635
636
  state through a code state that checks the returns and sends the work back
636
637
  with what is missing. Each entry is a bare
637
638
  run-variable name (**untyped**: any value, `null` included) or a strict object
638
- `{ name, type?, description? }` naming one; the spellings mix in one list and
639
+ `{ name, type?, description?, …rules }` naming one; the spellings mix in one list and
639
640
  names are distinct across both. What the agent must *do* to produce a
640
641
  variable still belongs in the `instructions` that set it. The names — with
641
- type and description when declared, as `name (type) — description` — are
642
+ type, rules and description when declared, as
643
+ `name (type; rule; rule) — description` — are
642
644
  rendered into the prompt under the trigger's entry state, so the agent is told
643
645
  what to produce before it can be failed for omitting it. A trigger's
644
646
  `requires:` also **guarantees** the variable for `${{…}}` guards, so `validate`
@@ -654,9 +656,37 @@ states:
654
656
  refused before any model call), **at the write** (`archmax_set_variables` of a
655
657
  mistyped typed return of the current trigger is a correctable refusal,
656
658
  nothing written) and **at completion** (a mistyped typed return rejects the
657
- run — in practice a code state's write). There are no enums, item or
658
- property schemas, ranges or optional inputs. An unknown `type`, an unknown
659
- entry key (`default:`) or an empty `description` fails load.
659
+ run — in practice a code state's write). There are no item or property
660
+ schemas and no optional inputs. An unknown `type`, an unknown entry key
661
+ (`default:`) or an empty `description` fails load.
662
+ - **Rules** say what a typed value must look like beyond its type, spelled as
663
+ JSON Schema keywords, and are held wherever the type is (start, write,
664
+ completion, a delegation call and its settle):
665
+
666
+ | Rule | On | Value |
667
+ | --- | --- | --- |
668
+ | `format` | `string` | `email` (WHATWG grammar, a domain with a TLD), `url` (absolute `http(s)://`, no credentials), `phone` (E.164, `+4930123456`) |
669
+ | `pattern` | `string` | a regex found anywhere in the value (anchor with `^…$`), ≤ 1,000 characters |
670
+ | `minLength`, `maxLength` | `string` | non-negative integers, counted in code points |
671
+ | `enum` | `string` | a non-empty list of distinct strings, matched exactly |
672
+ | `content` | `string` | `text`, `markdown` or `html`: a **declaration** for the host, never checked or sanitised |
673
+ | `minimum`, `maximum` | `integer`, `number` | numbers, inclusive |
674
+ | `minimum`, `maximum` | `date` | `YYYY-MM-DD` or `today` (UTC), inclusive |
675
+ | `minimum`, `maximum` | `date-time` | an RFC 3339 instant or `now`, inclusive |
676
+ | `minItems`, `maxItems` | `array` | non-negative integers |
677
+ | `accept` | `file` | extensions like `.pdf`, matched on the last extension, case-insensitively |
678
+ | `maxSize` | `file` | bytes, or `<n>KB` / `<n>MB` (1,000-based); checked where the file crosses a boundary |
679
+
680
+ Nothing is coerced or trimmed; a mistyped value reports its type, not a rule;
681
+ each entry reports only the first rule it breaks (`'quantity' must be at most
682
+ 100`). Load fails, naming the entry and key, for a rule on a type that does not
683
+ take it or on an untyped entry, `format` with `pattern`, a pattern that does not
684
+ compile or uses a lookaround or backreference, and inconsistent bounds (`min…`
685
+ above `max…`, an empty or repeated `enum`). A `pattern` runs in RE2 (linear
686
+ time, so no input can make it slow) and must also compile as an ECMA-262 `u`
687
+ regex, so RE2-only syntax like `(?i)` or `\pL` is refused. Add rules where a
688
+ caller outside the session supplies the value (a form, an MCP client), or where
689
+ the agent must produce a value of a set shape; the agent sees them in its prompt.
660
690
  - **A `file` value must name a readable file.** The pure rule checks only the
661
691
  path's shape (a host runs it in a browser). At the start, at the write, at
662
692
  completion and at a delegation call the runtime also requires a **file** (not a
@@ -59,9 +59,12 @@ states:
59
59
  requires: # variables a firing must supply (a caller's required params):
60
60
  - order_id # a bare name is untyped (any value, null included)
61
61
  - { name: due, type: date, description: The day it is due. } # typed: held at the boundary
62
+ - { name: contact, type: string, format: email } # a rule beside the type: held wherever the type is
62
63
  returns: [result_file] # variables the run guarantees on completion (a caller's result);
63
64
  # short of them: a child returns what it set + a `note`; a top-level run is rejected
64
65
  # entry types: string integer number boolean date date-time object array file
66
+ # rules: format pattern minLength maxLength enum content (string); minimum maximum
67
+ # (integer number date date-time); minItems maxItems (array); accept maxSize (file)
65
68
  instructions: >-
66
69
  Record the decision in scratchpad/refund.json, then archmax_advance to
67
70
  check-policy; never close the case yourself. If a note sends the case