@fevex/core 0.1.0-alpha.4 → 0.1.0-alpha.6

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 (42) hide show
  1. package/README.md +240 -11
  2. package/dist/agents/index.d.mts +1 -1
  3. package/dist/artifacts/index.d.mts +2 -0
  4. package/dist/artifacts/index.mjs +2 -0
  5. package/dist/artifacts-gUzemET7.mjs +440 -0
  6. package/dist/channels/index.d.mts +1 -1
  7. package/dist/evals/index.d.mts +4 -4
  8. package/dist/fevex-B4QY5Z6e.d.mts +119 -0
  9. package/dist/http/index.d.mts +65 -5
  10. package/dist/http/index.mjs +238 -16
  11. package/dist/{index-C-IFfCNw.d.mts → index-1cHr7KB_.d.mts} +3 -3
  12. package/dist/{index-CqOjvtQ9.d.mts → index-5p3q2yIp.d.mts} +4 -2
  13. package/dist/{index-hhbgvfIt.d.mts → index-BJktlD4E.d.mts} +2 -2
  14. package/dist/{index-CTIwrVf9.d.mts → index-BgKFd9yw.d.mts} +1 -1
  15. package/dist/{index-dkFyTNh4.d.mts → index-CbACw6xZ.d.mts} +2 -2
  16. package/dist/index-CpLDt6Rw.d.mts +118 -0
  17. package/dist/{index-CknU-glw.d.mts → index-CseuTR-F.d.mts} +2 -2
  18. package/dist/{index-CaE864Kz.d.mts → index-CzAi2Y_Z.d.mts} +45 -6
  19. package/dist/{index-DyyNLuwO.d.mts → index-DVw0zOc_.d.mts} +3 -3
  20. package/dist/{index-CrOId2px.d.mts → index-Df84VWmN.d.mts} +1 -1
  21. package/dist/index.d.mts +13 -13
  22. package/dist/index.mjs +904 -153
  23. package/dist/knowledge/index.d.mts +1 -1
  24. package/dist/model-stream-JQdHDDcj.mjs +131 -0
  25. package/dist/models/index.d.mts +1 -1
  26. package/dist/observability/index.d.mts +2 -2
  27. package/dist/policies/index.d.mts +1 -1
  28. package/dist/{model-stream-u2xMsEaf.mjs → run-support-CmZ6Xo6H.mjs} +41 -130
  29. package/dist/runtime/index.d.mts +2 -2
  30. package/dist/runtime/index.mjs +43 -1
  31. package/dist/sandbox/index.d.mts +1 -1
  32. package/dist/sandbox/index.mjs +1 -1
  33. package/dist/teams/index.d.mts +1 -1
  34. package/dist/testing/index.d.mts +8 -7
  35. package/dist/testing/index.mjs +94 -2
  36. package/dist/tools/index.d.mts +2 -2
  37. package/dist/types-B8laW1hM.d.mts +561 -0
  38. package/dist/workflows/index.d.mts +1 -1
  39. package/package.json +6 -2
  40. package/dist/fevex-BoPbZ-Tw.d.mts +0 -60
  41. package/dist/index-voIZhQXB.d.mts +0 -80
  42. package/dist/types-CuoRx12Q.d.mts +0 -333
package/README.md CHANGED
@@ -28,18 +28,26 @@ adapters, validation and tests without adopting a heavy runtime.
28
28
  npm install @fevex/core
29
29
  ```
30
30
 
31
- For official model adapters:
31
+ The npm release pipeline publishes exactly three official packages:
32
32
 
33
33
  ```bash
34
34
  npm install @fevex/core @fevex/openai
35
35
  npm install @fevex/core @fevex/deepseek
36
- npm install @fevex/core @fevex/mcp
37
- npm install @fevex/core @fevex/openapi
38
- npm install @fevex/core @fevex/sqlite
39
- npm install @fevex/core @fevex/postgres
40
- npm install @fevex/core @fevex/opentelemetry @opentelemetry/api
41
36
  ```
42
37
 
38
+ CI builds, typechecks, tests and tarball-smokes all nine packages. The
39
+ repository-only integrations below are **not published to npm** by the release
40
+ pipeline; use them from this repository until they are published:
41
+
42
+ | Package | Purpose |
43
+ | --- | --- |
44
+ | `@fevex/mcp` | Model Context Protocol tools and connections |
45
+ | `@fevex/openapi` | Tools generated from an OpenAPI document |
46
+ | `@fevex/sqlite` | SQLite run and session store |
47
+ | `@fevex/postgres` | PostgreSQL run and session store |
48
+ | `@fevex/opentelemetry` | OpenTelemetry trace and metric export |
49
+ | `@fevex/browser` | Browser automation tools |
50
+
43
51
  Schemas are optional. The examples use Zod 4, but any Standard
44
52
  Schema-compatible validator can be used:
45
53
 
@@ -47,6 +55,20 @@ Schema-compatible validator can be used:
47
55
  npm install zod
48
56
  ```
49
57
 
58
+ ## Compatibility & releases
59
+
60
+ FEVEX is pre-1.0. Documented imports from official packages are the public API;
61
+ `src/internal`, undocumented paths and checkpoint shapes are not. While in alpha,
62
+ `minor` releases may contain breaking changes with migration notes; `patch`
63
+ releases stay compatible. Store migrations are forward-only, checkpoints are
64
+ versioned and private, and downgrades are not supported.
65
+
66
+ Only the latest alpha is supported; pin exact versions in production. Releases
67
+ come from reviewed changesets, publish only the three official packages, and
68
+ place alpha versions on the npm `latest` tag. Read the full
69
+ [compatibility and release policy](https://fevex.dev/docs/compatibility/) before
70
+ upgrading a durable deployment.
71
+
50
72
  ## Quickstart
51
73
 
52
74
  This example executes a complete model-tool-model cycle without network access:
@@ -568,6 +590,31 @@ Hosts pass authenticated `ExecutionContext` separately to `handler(request,
568
590
  SSE response never cancels its run. Cancellation is explicit through
569
591
  `client.cancelRun(run.id)`.
570
592
 
593
+ Artifacts use the same handler:
594
+
595
+ ```ts
596
+ const handler = createFevexHttpHandler({
597
+ fevex: app,
598
+ artifacts: artifactStore, // FileSystemArtifactStore or S3ArtifactStore
599
+ artifactCatalog: artifactCatalog, // optional; enables listing by run
600
+ authorizeArtifact(access) {
601
+ return access.context?.actor?.id === 'alice';
602
+ },
603
+ });
604
+ ```
605
+
606
+ Routes:
607
+
608
+ - `GET /v1/artifacts/:id` streams the bytes with `content-type`,
609
+ `content-length`, `content-disposition`, `etag` and artifact headers.
610
+ - `HEAD /v1/artifacts/:id` returns the same metadata without a body.
611
+ - `DELETE /v1/artifacts/:id` deletes bytes and catalog metadata.
612
+ - `GET /v1/runs/:runId/artifacts?limit=100` lists descriptors for a run.
613
+
614
+ The client exposes `getArtifact`, `listArtifacts` and `deleteArtifact`. Keep the
615
+ bucket private; the handler authorizes the request and streams the bytes, or a
616
+ host can use the descriptor to mint a short-lived signed URL.
617
+
571
618
  ## Approvals and durable runs
572
619
 
573
620
  Tools can declare risk, approval, idempotency, retries and credential names.
@@ -652,6 +699,28 @@ underlying work. External systems must enforce the supplied idempotency key to
652
699
  make keyed retries safe. Repeated tool call IDs are rejected within a run before
653
700
  Fevex repeats an effect.
654
701
 
702
+ ### Deadlines, admission and retention
703
+
704
+ Set `deadlineMs` on a run request to cap wall-clock time. An expired deadline
705
+ cancels the run with `run.cancelled` reason `timeout`; resuming or recovering
706
+ after the absolute deadline persists that cancellation instead of continuing.
707
+
708
+ `createFevex({ admission })` limits concurrent top-level runs globally or per
709
+ tenant. The default tenant key is a non-empty `context.attributes.tenantId`;
710
+ `tenantKey` and `authorize` support host-specific quotas. Counts are local to
711
+ one runtime process.
712
+
713
+ `createFevex({ limits: { maxEventsPerRun } })` caps non-control events per run.
714
+ Pause, resume, approval, elicitation, wait and terminal events are always
715
+ persisted so a run can always reach a durable state; use retention for a total
716
+ storage cap.
717
+
718
+ Terminal runs can be purged with `app.purgeRuns({ before, statuses, limit })`.
719
+ SQLite and PostgreSQL implement the retention capability; custom stores can add
720
+ `purgeRuns` to opt in. The API deletes only terminal runs and sessions left
721
+ without runs; active work is untouched. Artifact retention and per-event payload
722
+ byte limits remain host policies.
723
+
655
724
  ## Observability
656
725
 
657
726
  Add trace exporters to the application configuration; agent definitions stay
@@ -683,8 +752,50 @@ Traces contain only metadata by default. Output and safe error capture require
683
752
  an explicit `content.include` policy; sensitive object keys are redacted before
684
753
  an optional application redactor runs. Exporters run outside the run path: their
685
754
  errors never change the run result, and `flushObservability()` reports pending
686
- export failures. OpenTelemetry SDK setup, OTLP export and shutdown remain
687
- application responsibilities.
755
+ export failures. Export work is bounded and deduplicated:
756
+
757
+ ```ts
758
+ const app = createFevex({
759
+ models,
760
+ agents,
761
+ observability: {
762
+ exporters: [createOpenTelemetryExporter()],
763
+ exportQueue: {
764
+ concurrency: 4,
765
+ maxQueued: 100,
766
+ timeoutMs: 30_000,
767
+ maxFailures: 100,
768
+ },
769
+ },
770
+ });
771
+
772
+ await app.flushObservability({ timeoutMs: 5_000 });
773
+ console.log(app.getObservabilityStats());
774
+ ```
775
+
776
+ Workflow and team traces carry `kind` and a span per step. Agent steps expose
777
+ `childRunId`; child agent traces carry `parentRunId` and `rootRunId`, and tool
778
+ spans are nested under the model call that requested them. A dropped trace or a
779
+ failed export is counted in `getObservabilityStats()`, and the next
780
+ `flushObservability()` rejects with the failures accumulated since the previous
781
+ flush. OpenTelemetry SDK setup, OTLP export and shutdown remain application
782
+ responsibilities.
783
+
784
+ ## Graceful shutdown
785
+
786
+ `shutdown` stops admission, drains active runs, cancels what remains at the
787
+ deadline and flushes trace exports:
788
+
789
+ ```ts
790
+ const result = await app.shutdown({ timeoutMs: 30_000 });
791
+ console.log(result.timedOut, result.cancelledRunIds, result.observability);
792
+ ```
793
+
794
+ New starts, resumes and recoveries fail with `RUNTIME_CLOSED` (HTTP `503`) once
795
+ shutdown begins. The host closes its HTTP server, stores and external adapters
796
+ after `shutdown` returns. See
797
+ [Operations & soak tests](https://fevex.dev/docs/operations/) for crash recovery
798
+ and the 1–8 hour load harness.
688
799
 
689
800
  ## Evaluations
690
801
 
@@ -871,12 +982,128 @@ Context providers are lazy per run. Memory is a replaceable store; the built-in
871
982
  store is in-memory substring search, not embeddings, vector search or durable
872
983
  storage.
873
984
 
985
+ ## Artifacts
986
+
987
+ `@fevex/core/artifacts` stores large or binary outputs as references. Runs,
988
+ events and prompts carry an `ArtifactDescriptor`; bytes stay in an
989
+ `ArtifactStore`.
990
+
991
+ ```ts
992
+ import {
993
+ FileSystemArtifactStore,
994
+ InMemoryArtifactStore,
995
+ S3ArtifactStore,
996
+ type S3ObjectClient,
997
+ } from '@fevex/core/artifacts';
998
+
999
+ const artifacts = new FileSystemArtifactStore({
1000
+ rootDir: '.fevex/artifacts',
1001
+ maxBytes: 10 * 1024 * 1024,
1002
+ });
1003
+
1004
+ const descriptor = await artifacts.put(
1005
+ {
1006
+ filename: 'report.pdf',
1007
+ mimeType: 'application/pdf',
1008
+ bytes,
1009
+ },
1010
+ { tenantId: 'acme', runId: 'run-1' },
1011
+ );
1012
+
1013
+ const stored = await artifacts.get(descriptor.artifactId, { tenantId: 'acme' });
1014
+ ```
1015
+
1016
+ Use `InMemoryArtifactStore` for tests. For S3, R2, MinIO or another
1017
+ S3-compatible service, wrap its SDK with the small `S3ObjectClient` interface;
1018
+ Fevex does not ship an object-storage SDK:
1019
+
1020
+ ```ts
1021
+ const client: S3ObjectClient = {
1022
+ async putObject({ key, body, contentType }) {
1023
+ await s3.send(new PutObjectCommand({
1024
+ Bucket,
1025
+ Key: key,
1026
+ Body: body,
1027
+ ContentType: contentType,
1028
+ }));
1029
+ },
1030
+ async getObject({ key }) {
1031
+ try {
1032
+ const result = await s3.send(new GetObjectCommand({ Bucket, Key: key }));
1033
+ return new Uint8Array(await result.Body!.transformToByteArray());
1034
+ } catch (error) {
1035
+ if ((error as { name?: string }).name === 'NoSuchKey') return null;
1036
+ throw error;
1037
+ }
1038
+ },
1039
+ async deleteObject({ key }) {
1040
+ await s3.send(new DeleteObjectCommand({ Bucket, Key: key }));
1041
+ },
1042
+ };
1043
+
1044
+ const artifacts = new S3ArtifactStore({ client, prefix: 'fevex' });
1045
+ ```
1046
+
1047
+ The bucket should stay private. The host authorizes the actor and serves a
1048
+ short-lived signed URL or streams the bytes; do not expose bucket URLs to the
1049
+ model. This subpath is local-first: use the filesystem store for development and
1050
+ single-node deployments, and the S3-compatible store for multi-instance
1051
+ production.
1052
+
1053
+ For a queryable metadata index, compose the byte store with a catalog:
1054
+
1055
+ ```ts
1056
+ import { CatalogedArtifactStore, FileSystemArtifactStore } from '@fevex/core/artifacts';
1057
+ import { createSQLiteArtifactCatalog } from '@fevex/sqlite';
1058
+
1059
+ const catalog = createSQLiteArtifactCatalog({ filename: '.fevex/artifacts.db' });
1060
+ const artifacts = new CatalogedArtifactStore({
1061
+ store: new FileSystemArtifactStore({ rootDir: '.fevex/artifacts' }),
1062
+ catalog,
1063
+ });
1064
+
1065
+ const records = await artifacts.list({ runId: 'run-1' }, { tenantId: 'acme' });
1066
+ await artifacts.deleteByRun('run-1', { tenantId: 'acme' });
1067
+ ```
1068
+
1069
+ `@fevex/postgres` exposes the same catalog contract with
1070
+ `createPostgresArtifactCatalog`. The catalog stores only metadata; bytes stay in
1071
+ the filesystem or object storage.
1072
+
1073
+ Pass the store to `createFevex` to expose it to tools as `context.artifacts`:
1074
+
1075
+ ```ts
1076
+ const save = defineTool({
1077
+ name: 'save_report',
1078
+ async execute(_input, context) {
1079
+ return context.artifacts!.put({
1080
+ filename: 'report.txt',
1081
+ mimeType: 'text/plain',
1082
+ bytes: new TextEncoder().encode('report'),
1083
+ });
1084
+ },
1085
+ });
1086
+
1087
+ createFevex({
1088
+ models,
1089
+ agents,
1090
+ tools: [save],
1091
+ artifacts,
1092
+ });
1093
+ ```
1094
+
1095
+ The runtime injects `runId`, `sessionId`, tenant and actor into every artifact
1096
+ call. Each successful `put` emits `artifact.created` with the descriptor before
1097
+ `tool.completed`; a tool that writes and then fails still leaves the event and
1098
+ the artifact available.
1099
+
874
1100
  ## Public Exports
875
1101
 
876
1102
  | Import | Purpose |
877
1103
  | --- | --- |
878
1104
  | `@fevex/core` | Common runtime, definitions and contracts |
879
1105
  | `@fevex/core/agents` | Agent definitions |
1106
+ | `@fevex/core/artifacts` | Artifact descriptors, local stores and S3-compatible adapter |
880
1107
  | `@fevex/core/channels` | Channel adapters and message handling |
881
1108
  | `@fevex/core/knowledge` | Context providers, skills and memory contracts |
882
1109
  | `@fevex/core/models` | Provider-neutral model contracts |
@@ -886,7 +1113,7 @@ storage.
886
1113
  | `@fevex/core/runtime` | Runs, sessions and store contracts |
887
1114
  | `@fevex/core/sandbox` | Sandbox contract and local development sandbox |
888
1115
  | `@fevex/core/policies` | Authorization policy contracts |
889
- | `@fevex/core/observability` | Trace, redaction and cost contracts |
1116
+ | `@fevex/core/observability` | Trace, bounded export queue, redaction and cost contracts |
890
1117
  | `@fevex/core/evals` | Datasets, scorers, reporters and regressions |
891
1118
  | `@fevex/core/testing` | Deterministic testing helpers |
892
1119
 
@@ -959,8 +1186,10 @@ limit for the initial SSE read and every subsequent read. Full pages drain
959
1186
  without the polling delay; short pages wait for `pollIntervalMs`. Stream demand
960
1187
  controls progress, so a slow consumer retains at most one page plus the stream's
961
1188
  single queued frame, rather than buffering the run's entire history. Disconnecting
962
- cancels polling. This bounds event counts, not the byte size of an individual event;
963
- per-event payload limits and data retention remain host responsibilities.
1189
+ cancels polling. `maxConnections` caps concurrent SSE streams. This bounds event
1190
+ counts, not the byte size of an individual event; per-event payload limits remain
1191
+ host responsibilities. Use `purgeRuns` for configurable retention of terminal
1192
+ runs.
964
1193
 
965
1194
  ### Run model identity
966
1195
 
@@ -1,2 +1,2 @@
1
- import { n as AgentLimits, r as defineAgent, t as AgentDefinition } from "../index-CaE864Kz.mjs";
1
+ import { n as AgentLimits, r as defineAgent, t as AgentDefinition } from "../index-CzAi2Y_Z.mjs";
2
2
  export { AgentDefinition, AgentLimits, defineAgent };
@@ -0,0 +1,2 @@
1
+ import { A as ArtifactError, C as FileSystemArtifactStore, D as ArtifactCatalog, E as CatalogedArtifactStoreOptions, F as ArtifactStore, I as ArtifactStoreContext, L as ArtifactWrite, M as ArtifactId, N as ArtifactQuery, O as ArtifactContent, P as ArtifactRecord, R as artifactTenantId, S as InMemoryArtifactCatalog, T as CatalogedArtifactStore, _ as S3ArtifactStore, b as InMemoryArtifactStore, j as ArtifactErrorCode, k as ArtifactDescriptor, v as S3ArtifactStoreOptions, w as FileSystemArtifactStoreOptions, x as InMemoryArtifactStoreOptions, y as S3ObjectClient, z as assertArtifactId } from "../types-B8laW1hM.mjs";
2
+ export { ArtifactCatalog, ArtifactContent, ArtifactDescriptor, ArtifactError, ArtifactErrorCode, ArtifactId, ArtifactQuery, ArtifactRecord, ArtifactStore, ArtifactStoreContext, ArtifactWrite, CatalogedArtifactStore, CatalogedArtifactStoreOptions, FileSystemArtifactStore, FileSystemArtifactStoreOptions, InMemoryArtifactCatalog, InMemoryArtifactStore, InMemoryArtifactStoreOptions, S3ArtifactStore, S3ArtifactStoreOptions, S3ObjectClient, artifactTenantId, assertArtifactId };
@@ -0,0 +1,2 @@
1
+ import { a as CatalogedArtifactStore, c as assertArtifactId, i as FileSystemArtifactStore, n as InMemoryArtifactStore, o as ArtifactError, r as InMemoryArtifactCatalog, s as artifactTenantId, t as S3ArtifactStore } from "../artifacts-gUzemET7.mjs";
2
+ export { ArtifactError, CatalogedArtifactStore, FileSystemArtifactStore, InMemoryArtifactCatalog, InMemoryArtifactStore, S3ArtifactStore, artifactTenantId, assertArtifactId };