workspai 0.75.2 → 0.77.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.
- package/README.md +2 -2
- package/contracts/agent-framework-capabilities.v1.json +2 -2
- package/contracts/cli-runtime-command-inventory.v1.snapshot.json +12 -0
- package/contracts/create-planner-capabilities.v1.json +48 -0
- package/contracts/extension-cli-compatibility.v1.json +4 -2
- package/contracts/published-contract-catalog.v1.json +10 -0
- package/contracts/runtime-command-surface.v1.json +5 -1
- package/contracts/workspace-intelligence/agent-framework-admission-candidate.v2.json +217 -0
- package/contracts/workspace-intelligence/agent-framework-conformance-report.v2.json +274 -0
- package/contracts/workspace-intelligence/workspace-model.v1.json +4 -0
- package/contracts/workspace-intelligence-architecture.v1.json +7 -3
- package/dist/analyze-TJM66CPF.js +1 -0
- package/dist/autopilot-release-C7Q4OTPY.js +1 -0
- package/dist/capabilities-command-TIBIKWPK.js +1 -0
- package/dist/{chunk-K52IQX3J.js → chunk-223SWPTL.js} +1 -1
- package/dist/chunk-3EMAC3MF.js +4 -0
- package/dist/{chunk-GDOO2YZW.js → chunk-3EPR3D5Q.js} +1 -1
- package/dist/chunk-3SQIV3F4.js +1 -0
- package/dist/{chunk-ZI54C2AO.js → chunk-475GQJ2D.js} +1 -1
- package/dist/{chunk-P36TACKN.js → chunk-47UR6ZH4.js} +1 -1
- package/dist/{chunk-VHMDWRDG.js → chunk-4BPZJR4Z.js} +4 -4
- package/dist/{chunk-VWBWDDU2.js → chunk-4CXV3PPV.js} +1 -1
- package/dist/chunk-4ZUBPFSO.js +6 -0
- package/dist/chunk-5KXOV7W4.js +1 -0
- package/dist/chunk-6BO4QHKA.js +1 -0
- package/dist/{chunk-OA2YJN22.js → chunk-DWDYLKVW.js} +1 -1
- package/dist/{chunk-KDVNRNDU.js → chunk-DWKCFHHL.js} +1 -1
- package/dist/{chunk-EP7SUMAX.js → chunk-E7WJ2QX7.js} +1 -1
- package/dist/{chunk-FNVWDXK2.js → chunk-GLBFY7AB.js} +5 -5
- package/dist/{chunk-ZGVODK5C.js → chunk-HRVHQBTA.js} +1 -1
- package/dist/{chunk-WHBKKJ7L.js → chunk-IAXRGH4Q.js} +1 -1
- package/dist/chunk-IDETNYCF.js +1 -0
- package/dist/chunk-IHWS3ALP.js +2 -0
- package/dist/{chunk-FZWLWFR4.js → chunk-J2MPBSQJ.js} +1 -1
- package/dist/{chunk-PFAGXI3G.js → chunk-JVZA35OL.js} +1 -1
- package/dist/chunk-LUPKDFQ3.js +7 -0
- package/dist/chunk-N7DOKE7V.js +2 -0
- package/dist/chunk-O3TVVQ6X.js +6 -0
- package/dist/chunk-P5LI5DL3.js +1 -0
- package/dist/{chunk-4JXJRIJM.js → chunk-QCX6BO2M.js} +1 -1
- package/dist/chunk-SC43A6LH.js +97 -0
- package/dist/chunk-SEZTSMRR.js +1 -0
- package/dist/{chunk-COOVCORC.js → chunk-SVO2GGTV.js} +1 -1
- package/dist/{chunk-5K4O3TAW.js → chunk-TGNPMOM6.js} +1 -1
- package/dist/chunk-UNEK3VVR.js +2684 -0
- package/dist/{chunk-IKBE3HOH.js → chunk-UP3UWAJV.js} +1 -1
- package/dist/{chunk-LFY7KTPD.js → chunk-UTIK3K3M.js} +1 -1
- package/dist/{chunk-WXUCAVFT.js → chunk-V6HVDVKJ.js} +8 -8
- package/dist/chunk-WC2K5QFI.js +10 -0
- package/dist/{chunk-DTNOF3MP.js → chunk-X5XFT5UZ.js} +1 -1
- package/dist/{chunk-ADHX7D3F.js → chunk-ZIWWE4BQ.js} +1 -1
- package/dist/{create-ZFSFWAW3.js → create-YPAZJYCE.js} +1 -1
- package/dist/{doctor-4KL4XUCS.js → doctor-W5PXJ5FL.js} +1 -1
- package/dist/{goal-lifecycle-EXQZD7IA.js → goal-lifecycle-5R55CA7H.js} +1 -1
- package/dist/{goal-pack-DKJU2DEP.js → goal-pack-IS6GGJPH.js} +1 -1
- package/dist/index.d.ts +12 -6
- package/dist/index.js +181 -171
- package/dist/{pipeline-4GVAOCEN.js → pipeline-LW3SW2WT.js} +1 -1
- package/dist/platform-capabilities-RWOWND5Q.js +1 -0
- package/dist/{project-agent-entry-7QKNEEXP.js → project-agent-entry-5TYKK5IV.js} +1 -1
- package/dist/{project-intelligence-lens-IHRYCLNU.js → project-intelligence-lens-TEOSTKNU.js} +1 -1
- package/dist/{project-test-coverage-3P5FH6E5.js → project-test-coverage-T4TIWGKN.js} +1 -1
- package/dist/proof-carrying-change-2TKRADCW.js +1 -0
- package/dist/{pythonRapidkitExec-UMFLDIYR.js → pythonRapidkitExec-S35OEIEF.js} +1 -1
- package/dist/{verified-goal-XI4RQESU.js → verified-goal-RN4TOV34.js} +1 -1
- package/dist/{workspace-EYXAKMVI.js → workspace-A33YMF2N.js} +1 -1
- package/dist/{workspace-agent-sync-SN55KT6N.js → workspace-agent-sync-VCA4G4DT.js} +1 -1
- package/dist/{workspace-context-PW6ESEHH.js → workspace-context-YBWLSKR6.js} +1 -1
- package/dist/{workspace-contract-FPLFL4G3.js → workspace-contract-3QUZDBMM.js} +1 -1
- package/dist/{workspace-explain-TVQ5IF5D.js → workspace-explain-NXYRAQFI.js} +1 -1
- package/dist/{workspace-foundation-DWIJPZRH.js → workspace-foundation-DZ52PECX.js} +1 -1
- package/dist/{workspace-graph-stream-RUTNWLQB.js → workspace-graph-stream-4VT46HZ7.js} +1 -1
- package/dist/{workspace-intelligence-4CA2CSPZ.js → workspace-intelligence-FKYQQDJ6.js} +1 -1
- package/dist/{workspace-intelligence-runner-VM5SXXAT.js → workspace-intelligence-runner-3K2JZH6Q.js} +1 -1
- package/dist/{workspace-knowledge-graph-JXN2ZOAF.js → workspace-knowledge-graph-CPBKNXQI.js} +1 -1
- package/dist/workspace-knowledge-graph-snapshot-67XDXUOT.js +1 -0
- package/dist/{workspace-mcp-serve-4WN4CSD7.js → workspace-mcp-serve-UXPKX7K6.js} +1 -1
- package/dist/{workspace-model-D4IECQML.js → workspace-model-POCPMNRT.js} +1 -1
- package/dist/{workspace-onboarding-6XWDKLM5.js → workspace-onboarding-KLG3GG7S.js} +1 -1
- package/dist/{workspace-registry-summary-Y3ET36NH.js → workspace-registry-summary-M4WMFDQ4.js} +1 -1
- package/dist/{workspace-repair-engine-HBUXRHDY.js → workspace-repair-engine-2VGN42QD.js} +1 -1
- package/dist/workspace-run-5YQR7GEZ.js +1 -0
- package/dist/{workspace-verify-OOAZ3NMZ.js → workspace-verify-PLAKTF3J.js} +1 -1
- package/dist/{workspace-watch-BNM5B6HU.js → workspace-watch-VNU4KVYN.js} +1 -1
- package/docs/README.md +4 -2
- package/docs/agent-framework-adapters.md +168 -39
- package/docs/ci-workflows.md +40 -22
- package/docs/commands-reference.md +19 -8
- package/docs/create-planner-capabilities.md +1 -0
- package/docs/creating-workspaces-and-projects.md +28 -9
- package/docs/doctor-command.md +9 -4
- package/docs/model-gateways.md +204 -0
- package/docs/native-kit-baselines.md +4 -2
- package/docs/workspace-run.md +3 -1
- package/package.json +5 -1
- package/scripts/enterprise-package-smoke.mjs +200 -5
- package/dist/analyze-6UEBC5OJ.js +0 -1
- package/dist/autopilot-release-H5TO6NYY.js +0 -1
- package/dist/capabilities-command-VK3LQLP2.js +0 -1
- package/dist/chunk-3N27P3KO.js +0 -7
- package/dist/chunk-3RNWBFRP.js +0 -4
- package/dist/chunk-66O62XNJ.js +0 -97
- package/dist/chunk-7NKM6EHE.js +0 -7
- package/dist/chunk-BR6QIYQS.js +0 -1
- package/dist/chunk-DFREJHG7.js +0 -1
- package/dist/chunk-E42IFQFR.js +0 -6
- package/dist/chunk-EWD6QTAM.js +0 -2
- package/dist/chunk-G5UCEXP6.js +0 -1
- package/dist/chunk-JKAAKE4Z.js +0 -6
- package/dist/chunk-LARREYZN.js +0 -1
- package/dist/chunk-RGNCL5OB.js +0 -1
- package/dist/chunk-SZHRPELL.js +0 -1
- package/dist/chunk-VXFIMEC6.js +0 -2
- package/dist/chunk-X7OI24LO.js +0 -418
- package/dist/platform-capabilities-DB4BZPTD.js +0 -1
- package/dist/proof-carrying-change-O37XUPIZ.js +0 -1
- package/dist/workspace-knowledge-graph-snapshot-KBNUXA64.js +0 -1
- package/dist/workspace-run-VN7KV4BU.js +0 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# AI Gateway
|
|
2
|
+
|
|
3
|
+
AI Gateway is a first-class Workspai project category for unified model access
|
|
4
|
+
and routing. It is not an Agent Framework.
|
|
5
|
+
|
|
6
|
+
## Why Gateway is not Agent Framework
|
|
7
|
+
|
|
8
|
+
Agent Framework owns agent loops, tools, handoffs, state, and orchestration.
|
|
9
|
+
AI Gateway owns model and provider access, routing preferences, fallbacks,
|
|
10
|
+
privacy policy, and normalized transport behavior.
|
|
11
|
+
|
|
12
|
+
A model identifier is runtime configuration, not a project kit. Workspai owns
|
|
13
|
+
project generation, governance, context, lifecycle, verification, workspace
|
|
14
|
+
integration, and proof. OpenRouter owns provider and model routing. Generated
|
|
15
|
+
projects do not reimplement OpenRouter's routing algorithms.
|
|
16
|
+
|
|
17
|
+
Future agent-to-gateway composition should consume the generated Model Gateway
|
|
18
|
+
port. Do not copy these templates into an Agent Framework kit.
|
|
19
|
+
|
|
20
|
+
## Current kits
|
|
21
|
+
|
|
22
|
+
These kits ship as source-ready. That is not Workspai release admission and
|
|
23
|
+
does not label them `stable` or `qualified`. SDK `1.x` stability is an upstream
|
|
24
|
+
classification, not a Workspai release gate.
|
|
25
|
+
|
|
26
|
+
| Kit | Runtime | Official Client SDK | Reviewed |
|
|
27
|
+
| --- | --- | --- | --- |
|
|
28
|
+
| `gateway.openrouter.typescript` | Node.js `>=20` | `@openrouter/sdk` `1.3.11` | 2026-09-21 |
|
|
29
|
+
| `gateway.openrouter.python` | Python `>=3.10` | `openrouter` `1.2.11` | 2026-09-21 |
|
|
30
|
+
|
|
31
|
+
Aliases: `openrouter.typescript`, `gateway.openrouter.ts`, `openrouter-typescript`,
|
|
32
|
+
and the matching Python aliases. Bare `openrouter` is not an alias.
|
|
33
|
+
|
|
34
|
+
Interactive Create shows **AI Gateway** with the hint **Unified model access
|
|
35
|
+
and routing** after at least one gateway kit is registered. Labels are:
|
|
36
|
+
|
|
37
|
+
- `AI Gateway · OpenRouter · TypeScript`
|
|
38
|
+
- `AI Gateway · OpenRouter · Python`
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx workspai create project gateway.openrouter.typescript <name>
|
|
42
|
+
npx workspai create project gateway.openrouter.python <name>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Create does not install dependencies, call a model, or write credentials.
|
|
46
|
+
|
|
47
|
+
Attach is not supported for AI Gateway in this release. Do not use
|
|
48
|
+
`agent framework attach` or any gateway-specific attach command. Adopt an
|
|
49
|
+
existing OpenRouter project only by creating a new gateway kit or by adding
|
|
50
|
+
the generated starter beside user-owned code. Repeated Create is not Attach.
|
|
51
|
+
|
|
52
|
+
## Version upgrades
|
|
53
|
+
|
|
54
|
+
Exact SDK pins live only in
|
|
55
|
+
[`version-baselines.v1.json`](../src/model-gateways/version-baselines.v1.json).
|
|
56
|
+
`releaseChannel: stable` means the upstream SDK release is stable. It does not
|
|
57
|
+
mean the Workspai adapter passed Linux, macOS, and Windows qualification.
|
|
58
|
+
|
|
59
|
+
The supported upgrade path is read-only until a human reviews the proposal:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
discover → propose → review → qualify → merge
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm --workspace workspai run propose:model-gateway:versions -- \
|
|
67
|
+
--baseline src/model-gateways/version-baselines.v1.json \
|
|
68
|
+
--report test-results/model-gateway-version-discovery.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The command does not commit, push, open a pull request, or write the baseline
|
|
72
|
+
unless `--write` is passed after the on-disk file matches the validated
|
|
73
|
+
in-memory document and every candidate agrees across registry and GitHub.
|
|
74
|
+
A normal SDK upgrade should not require editing generator source when the
|
|
75
|
+
upstream contract is compatible. Three-OS qualification must be green on the
|
|
76
|
+
same commit before a Workspai release can present these kits as qualified.
|
|
77
|
+
|
|
78
|
+
## Intentionally unsupported languages
|
|
79
|
+
|
|
80
|
+
The official Go SDK (`github.com/OpenRouterTeam/go-sdk`) was evaluated on
|
|
81
|
+
2026-09-21. The upstream README classifies the current `0.x` line as beta and
|
|
82
|
+
warns that breaking changes may ship in minor releases. proxy.golang.org
|
|
83
|
+
reported `v0.8.11`. Go is excluded from the stable Create surface until
|
|
84
|
+
upstream classifies a release line as stable.
|
|
85
|
+
|
|
86
|
+
The OpenRouter Agent SDK (`@openrouter/agent`) belongs to the agent-runtime
|
|
87
|
+
dimension. It is not used by AI Gateway kits and is not added as
|
|
88
|
+
`agent.openrouter.typescript` in this family.
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
Required environment:
|
|
93
|
+
|
|
94
|
+
- `OPENROUTER_API_KEY` — server-side only
|
|
95
|
+
- `OPENROUTER_MODEL` — chosen by the operator; Workspai does not default a
|
|
96
|
+
billable model
|
|
97
|
+
|
|
98
|
+
Optional attribution maps to the official SDK fields:
|
|
99
|
+
|
|
100
|
+
- TypeScript: `httpReferer`, `appTitle` via `OPENROUTER_HTTP_REFERER` and
|
|
101
|
+
`OPENROUTER_APP_TITLE`
|
|
102
|
+
- Python: `http_referer`, `x_open_router_title` via `OPENROUTER_HTTP_REFERER`
|
|
103
|
+
and `OPENROUTER_X_OPEN_ROUTER_TITLE`
|
|
104
|
+
|
|
105
|
+
Routing and privacy policy live in source-controlled `gateway.policy.json`.
|
|
106
|
+
Field names match the pinned SDK for that language. Unknown fields are rejected
|
|
107
|
+
fail-closed in both languages. Supported controls:
|
|
108
|
+
|
|
109
|
+
| Official field | TypeScript policy | Python policy | Validation |
|
|
110
|
+
| --- | --- | --- | --- |
|
|
111
|
+
| model fallbacks | `models` | `models` | unique non-empty strings; must not repeat `OPENROUTER_MODEL` |
|
|
112
|
+
| `allowFallbacks` | `allowFallbacks` | `allow_fallbacks` | boolean when present |
|
|
113
|
+
| `order` / `only` / `ignore` | same camelCase | same snake_case | unique non-empty strings; `only`∩`ignore` empty; `order` must not include ignored providers |
|
|
114
|
+
| `sort` | string or `{ by, partition }` | string or `{ by, partition }` | `price`/`throughput`/`latency`/`exacto`; `partition` is `model` or `none` |
|
|
115
|
+
| `quantizations` | camelCase list | snake_case list | pinned SDK enum values |
|
|
116
|
+
| `requireParameters` | `requireParameters` | `require_parameters` | boolean when present |
|
|
117
|
+
| `zdr` | `zdr` | `zdr` | boolean; cannot combine with `dataCollection`/`data_collection` `allow` |
|
|
118
|
+
| `dataCollection` | `dataCollection` | `data_collection` | `allow` or `deny` |
|
|
119
|
+
| `enforceDistillableText` | `enforceDistillableText` | `enforce_distillable_text` | boolean when present; both pinned SDKs expose this field |
|
|
120
|
+
| `maxPrice` | `maxPrice` | `max_price` | object with `prompt`/`completion`/`request`/`image`/`audio` as non-negative numeric strings that remain finite after numeric interpretation |
|
|
121
|
+
| `preferredMinThroughput` | number or `{ p50, p75, p90, p99 }` | same | finite non-negative numbers |
|
|
122
|
+
| `preferredMaxLatency` | number or `{ p50, p75, p90, p99 }` | same | finite non-negative numbers |
|
|
123
|
+
| timeout | `timeoutMs` | `timeout_ms` | integer 1–600000; env overrides with a digit string |
|
|
124
|
+
| attribution | `httpReferer`, `appTitle` | `http_referer`, `x_open_router_title` | strings when present |
|
|
125
|
+
|
|
126
|
+
`exacto` is part of the pinned SDK `ProviderSort` enums, not a Workspai extension.
|
|
127
|
+
Malformed JSON and wrong types raise `GatewayConfigurationError` before SDK
|
|
128
|
+
construction. Contradictory policy, including ZDR combined with
|
|
129
|
+
`dataCollection: "allow"`, fails before a network request.
|
|
130
|
+
|
|
131
|
+
Omitted privacy or routing fields leave OpenRouter upstream defaults in
|
|
132
|
+
effect. The SDKs document `dataCollection` / `data_collection` default as
|
|
133
|
+
`allow` when unset. Application-side retries are set to strategy `none` so they
|
|
134
|
+
cannot duplicate billable requests. OpenRouter may still apply provider
|
|
135
|
+
fallbacks when `allowFallbacks` / `allow_fallbacks` is not `false`.
|
|
136
|
+
|
|
137
|
+
Capabilities such as tools, JSON schema, structured output, images, audio, and
|
|
138
|
+
embeddings vary by model and provider. These starters only claim chat
|
|
139
|
+
generation and streaming.
|
|
140
|
+
|
|
141
|
+
## Security
|
|
142
|
+
|
|
143
|
+
- Never commit, log, or serialize API keys.
|
|
144
|
+
- Generated clients are server-side only. Do not expose `OPENROUTER_API_KEY`
|
|
145
|
+
through browser bundles or frontend environment prefixes such as `VITE_` or
|
|
146
|
+
`NEXT_PUBLIC_`.
|
|
147
|
+
- Diagnostics redact Authorization headers, API keys, URL secrets, and request
|
|
148
|
+
bodies.
|
|
149
|
+
- TLS verification is not disabled.
|
|
150
|
+
- Telemetry and prompt recording are not added.
|
|
151
|
+
|
|
152
|
+
## Lifecycle
|
|
153
|
+
|
|
154
|
+
After local install, documented commands are:
|
|
155
|
+
|
|
156
|
+
TypeScript: `npm install`, `npm test`, `npm run typecheck`, `npm run build`,
|
|
157
|
+
`npm run smoke`, `npm start`.
|
|
158
|
+
|
|
159
|
+
Python: create a virtualenv, `python -m pip install -e .`, `python -m compileall .`,
|
|
160
|
+
`python -m unittest discover -s tests`, `python main.py --smoke`, `python main.py`.
|
|
161
|
+
|
|
162
|
+
Workspace Run uses those same manifests and the generated project's declared
|
|
163
|
+
polyglot unit commands. Stage commands, including `&&` chains and a multi-step
|
|
164
|
+
`start`, run as argv. They are not passed to a shell, so an absolute interpreter
|
|
165
|
+
path cannot be expanded by `/bin/sh`. `test` and `--smoke` inject a fake
|
|
166
|
+
transport. They do not require a live `OPENROUTER_API_KEY`.
|
|
167
|
+
|
|
168
|
+
Streaming uses the official Client SDK event stream. Opening and iterating the
|
|
169
|
+
stream are both normalized: configuration errors stay configuration errors,
|
|
170
|
+
timeouts and caller aborts stay recognizable, and other failures become
|
|
171
|
+
`GatewayUpstreamError` with redacted messages and preserved status / request id /
|
|
172
|
+
retry-after when the SDK exposes them. Cleanup is once-only and prefers, in
|
|
173
|
+
order: async iterator `return()` / generator `close()`, then SDK `close()`, then
|
|
174
|
+
SDK `cancel()`. A cleanup failure does not replace the primary error or convert
|
|
175
|
+
a successful completion into an error.
|
|
176
|
+
|
|
177
|
+
The TypeScript starter forwards `AbortSignal` through `chat.send` options,
|
|
178
|
+
including an already-aborted signal. Pinned `@openrouter/sdk` `1.3.11`
|
|
179
|
+
`EventStream` extends `ReadableStream` and does not expose a dedicated `close()`.
|
|
180
|
+
Cancellation is `ReadableStream` async-iterator `return()` → `cancel()`. If the
|
|
181
|
+
stream has already errored, `cancel()` may be a no-op; the gateway still drops
|
|
182
|
+
its own reference and remains usable for a later request. The Python starter
|
|
183
|
+
closes the SDK iterator first (`EventStream.generator.close()`), which is the
|
|
184
|
+
consumer `generator.close()` path. Python does not expose `AbortSignal`.
|
|
185
|
+
Application-side retries stay disabled. Timeouts use SDK `timeoutMs` /
|
|
186
|
+
`timeout_ms`. An empty successful completion returns an empty string.
|
|
187
|
+
|
|
188
|
+
Exact pins live in
|
|
189
|
+
[`version-baselines.v1.json`](../src/model-gateways/version-baselines.v1.json).
|
|
190
|
+
Do not copy versions into unrelated files.
|
|
191
|
+
|
|
192
|
+
## Qualification boundary
|
|
193
|
+
|
|
194
|
+
Workspai source readiness is not release qualification. These kits are not
|
|
195
|
+
described as `stable`, `release-ready`, `admitted`, or `qualified` until Linux,
|
|
196
|
+
macOS, and Windows CI prove generated-project installation and lifecycle on the
|
|
197
|
+
same commit SHA, and a later admission change records that evidence. The
|
|
198
|
+
dedicated workflow is `.github/workflows/model-gateway-qualification.yml`.
|
|
199
|
+
Path-triggered runs and manual `full` mode each qualify both the TypeScript and
|
|
200
|
+
Python OpenRouter adapters on Linux, macOS, and Windows. Manual `fast` mode
|
|
201
|
+
stays on Linux. There is no unused kit axis. Discovery is
|
|
202
|
+
`.github/workflows/model-gateway-version-discovery.yml`. Its job summary shows
|
|
203
|
+
the sdk-core candidate diff when registry and GitHub agree. A green job that
|
|
204
|
+
skipped installation or lifecycle is not qualified.
|
|
@@ -12,9 +12,11 @@ native kits:
|
|
|
12
12
|
This policy does not cover FastAPI or NestJS kits owned by the RapidKit Python
|
|
13
13
|
engine. It also does not cover generators delegated to an upstream official
|
|
14
14
|
CLI, such as Next.js, Astro, Angular, Vue, Svelte, Nuxt, or React Native.
|
|
15
|
-
Governed Microsoft Agent Framework kits are versioned
|
|
15
|
+
Governed Microsoft Agent Framework and OpenAI Agents SDK kits are versioned
|
|
16
|
+
separately through the
|
|
16
17
|
[Agent Framework Adapter Contract](./agent-framework-adapters.md); they are
|
|
17
|
-
not native HTTP service generators.
|
|
18
|
+
not native HTTP service generators. OpenRouter AI Gateway kits are versioned
|
|
19
|
+
through [AI Gateway](./model-gateways.md) and are not Agent Framework kits.
|
|
18
20
|
|
|
19
21
|
## Current tested baseline
|
|
20
22
|
|
package/docs/workspace-run.md
CHANGED
|
@@ -52,7 +52,9 @@ Microsoft Agent Framework projects keep their executable manifest under
|
|
|
52
52
|
`agents/<instance>/`. Workspace Run treats that nested `pyproject.toml` or
|
|
53
53
|
`.csproj` as its own unit (`python3 -m compileall .`,
|
|
54
54
|
`python3 -m unittest discover -s tests`, `python3 main.py`, or the matching
|
|
55
|
-
.NET commands).
|
|
55
|
+
.NET commands). A Python unit with `main.py` uses `compileall` even when
|
|
56
|
+
`pyproject.toml` declares `[build-system]`; `python -m build` remains only for
|
|
57
|
+
packaging projects that have no agent entrypoint. An empty legacy root manifest is ignored only when it still
|
|
56
58
|
matches the exact older Workspai shell and a real `agents/primary` runtime
|
|
57
59
|
exists. Any user edit restores the root as an independent unit.
|
|
58
60
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workspai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Open-source workspace intelligence CLI for software systems: create, adopt, govern, verify, and align polyglot workspaces for humans, CI, IDEs, and AI agents.",
|
|
6
6
|
"keywords": [
|
|
@@ -115,9 +115,13 @@
|
|
|
115
115
|
"test:runtime-contract": "node scripts/runtime-acceptance-matrix.mjs --contract-only",
|
|
116
116
|
"test:agent-framework:python": "tsx scripts/smoke-microsoft-agent-framework-adapter.ts --runtime python",
|
|
117
117
|
"test:agent-framework:dotnet": "tsx scripts/smoke-microsoft-agent-framework-adapter.ts --runtime dotnet",
|
|
118
|
+
"test:agent-framework:openai:python": "tsx scripts/smoke-openai-agents-adapter.ts --runtime python",
|
|
119
|
+
"test:agent-framework:openai:typescript": "tsx scripts/smoke-openai-agents-adapter.ts --runtime typescript",
|
|
118
120
|
"verify:agent-framework:matrix": "tsx scripts/verify-agent-framework-conformance.ts --reports test-results/agent-framework-conformance",
|
|
119
121
|
"discover:agent-framework:versions": "tsx scripts/discover-agent-framework-versions.ts",
|
|
120
122
|
"propose:agent-framework:versions": "tsx scripts/propose-agent-framework-version-update.ts",
|
|
123
|
+
"discover:model-gateway:versions": "tsx scripts/propose-model-gateway-version-update.ts",
|
|
124
|
+
"propose:model-gateway:versions": "tsx scripts/propose-model-gateway-version-update.ts",
|
|
121
125
|
"promote:agent-framework:admission": "tsx scripts/promote-agent-framework-release-admission.ts",
|
|
122
126
|
"prepush:test:runtime-contract": "node scripts/run-cached-prepush-gate.mjs runtime-contract",
|
|
123
127
|
"test:runtime-matrix:full": "node scripts/runtime-acceptance-matrix.mjs --full",
|
|
@@ -9,6 +9,7 @@ import process from 'node:process';
|
|
|
9
9
|
const repoRoot = process.cwd();
|
|
10
10
|
const cliPath = path.join(repoRoot, 'dist', 'index.js');
|
|
11
11
|
const isolatedHome = fs.mkdtempSync(path.join(os.tmpdir(), 'workspai-enterprise-home-'));
|
|
12
|
+
let releaseAdmittedAdapterIds = new Set();
|
|
12
13
|
|
|
13
14
|
process.on('exit', () => {
|
|
14
15
|
fs.rmSync(isolatedHome, { recursive: true, force: true });
|
|
@@ -348,12 +349,43 @@ function assertCliContracts() {
|
|
|
348
349
|
}
|
|
349
350
|
|
|
350
351
|
const frameworks = parseTrailingJson(runCli(['agent', 'framework', 'list', '--json']));
|
|
352
|
+
if (frameworks.schemaVersion !== 'workspai.agent-framework-list.v1') {
|
|
353
|
+
fail(`unexpected agent framework list schema: ${frameworks.schemaVersion}`);
|
|
354
|
+
}
|
|
355
|
+
const adapters = Array.isArray(frameworks.adapters) ? frameworks.adapters : [];
|
|
356
|
+
const admittedIds = adapters
|
|
357
|
+
.filter((adapter) => adapter.status === 'admitted')
|
|
358
|
+
.map((adapter) => adapter.id)
|
|
359
|
+
.sort();
|
|
360
|
+
const expectedAdapterIds = [
|
|
361
|
+
'microsoft-agent-framework-dotnet',
|
|
362
|
+
'microsoft-agent-framework-python',
|
|
363
|
+
'openai-agents-python',
|
|
364
|
+
'openai-agents-typescript',
|
|
365
|
+
];
|
|
351
366
|
if (
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
frameworks.adapters.some((adapter) => adapter.status !== 'admitted')
|
|
367
|
+
admittedIds.length !== 0 &&
|
|
368
|
+
JSON.stringify(admittedIds) !== JSON.stringify(expectedAdapterIds)
|
|
355
369
|
) {
|
|
356
|
-
fail(
|
|
370
|
+
fail(
|
|
371
|
+
`published CLI does not expose the exact release-admitted framework adapters (admitted: ${
|
|
372
|
+
admittedIds.join(', ') || 'none'
|
|
373
|
+
})`
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
releaseAdmittedAdapterIds = new Set(admittedIds);
|
|
377
|
+
for (const openaiId of ['openai-agents-python', 'openai-agents-typescript']) {
|
|
378
|
+
const openai = adapters.find((adapter) => adapter.id === openaiId);
|
|
379
|
+
if (!openai) {
|
|
380
|
+
fail(`published CLI is missing implemented OpenAI adapter ${openaiId}`);
|
|
381
|
+
}
|
|
382
|
+
if (openai.stability !== 'stable') {
|
|
383
|
+
fail(
|
|
384
|
+
`${openaiId} must be labeled stable after the digest-changing promotion (observed: ${
|
|
385
|
+
openai.stability ?? 'missing'
|
|
386
|
+
})`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
357
389
|
}
|
|
358
390
|
|
|
359
391
|
log(`verified CLI contract surfaces for v${version.version}`);
|
|
@@ -390,6 +422,7 @@ function smokeCreateAgentFrameworkKits() {
|
|
|
390
422
|
{
|
|
391
423
|
kit: 'agent.microsoft.python',
|
|
392
424
|
name: 'python-agent',
|
|
425
|
+
expectCreate: releaseAdmittedAdapterIds.has('microsoft-agent-framework-python'),
|
|
393
426
|
expectedFiles: [
|
|
394
427
|
'README.md',
|
|
395
428
|
'.workspai/project.json',
|
|
@@ -404,6 +437,7 @@ function smokeCreateAgentFrameworkKits() {
|
|
|
404
437
|
{
|
|
405
438
|
kit: 'agent.microsoft.dotnet',
|
|
406
439
|
name: 'dotnet-agent',
|
|
440
|
+
expectCreate: releaseAdmittedAdapterIds.has('microsoft-agent-framework-dotnet'),
|
|
407
441
|
expectedFiles: [
|
|
408
442
|
'README.md',
|
|
409
443
|
'.workspai/project.json',
|
|
@@ -417,6 +451,41 @@ function smokeCreateAgentFrameworkKits() {
|
|
|
417
451
|
'agents/primary/README.md',
|
|
418
452
|
],
|
|
419
453
|
},
|
|
454
|
+
{
|
|
455
|
+
kit: 'agent.openai.python',
|
|
456
|
+
name: 'openai-python-agent',
|
|
457
|
+
expectCreate: releaseAdmittedAdapterIds.has('openai-agents-python'),
|
|
458
|
+
expectedFiles: [
|
|
459
|
+
'README.md',
|
|
460
|
+
'.workspai/project.json',
|
|
461
|
+
'.workspai/agent-frameworks/openai-agents-python/primary.json',
|
|
462
|
+
'agents/primary/main.py',
|
|
463
|
+
'agents/primary/workspai_context.py',
|
|
464
|
+
'agents/primary/agent.py',
|
|
465
|
+
'agents/primary/pyproject.toml',
|
|
466
|
+
'agents/primary/tests/test_context.py',
|
|
467
|
+
'agents/primary/.env.example',
|
|
468
|
+
'agents/primary/README.md',
|
|
469
|
+
],
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
kit: 'agent.openai.typescript',
|
|
473
|
+
name: 'openai-typescript-agent',
|
|
474
|
+
expectCreate: releaseAdmittedAdapterIds.has('openai-agents-typescript'),
|
|
475
|
+
expectedFiles: [
|
|
476
|
+
'README.md',
|
|
477
|
+
'.workspai/project.json',
|
|
478
|
+
'.workspai/agent-frameworks/openai-agents-typescript/primary.json',
|
|
479
|
+
'agents/primary/src/main.ts',
|
|
480
|
+
'agents/primary/src/workspai-context.ts',
|
|
481
|
+
'agents/primary/src/agent.ts',
|
|
482
|
+
'agents/primary/package.json',
|
|
483
|
+
'agents/primary/tsconfig.json',
|
|
484
|
+
'agents/primary/tests/context.test.ts',
|
|
485
|
+
'agents/primary/.env.example',
|
|
486
|
+
'agents/primary/README.md',
|
|
487
|
+
],
|
|
488
|
+
},
|
|
420
489
|
];
|
|
421
490
|
try {
|
|
422
491
|
for (const scenario of scenarios) {
|
|
@@ -430,6 +499,22 @@ function smokeCreateAgentFrameworkKits() {
|
|
|
430
499
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
431
500
|
}
|
|
432
501
|
);
|
|
502
|
+
const combined = `${result.stdout}\n${result.stderr}`;
|
|
503
|
+
if (scenario.expectCreate === false) {
|
|
504
|
+
if (result.status === 0) {
|
|
505
|
+
fail(`${scenario.kit} create succeeded before the stable digest was release-admitted`);
|
|
506
|
+
}
|
|
507
|
+
if (
|
|
508
|
+
!/not release-admitted|adapter (?:manifest|implementation) changed after release admission/i.test(
|
|
509
|
+
combined
|
|
510
|
+
)
|
|
511
|
+
) {
|
|
512
|
+
fail(
|
|
513
|
+
`${scenario.kit} failed closed without an admission blocker\n${result.stdout}\n${result.stderr}`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
433
518
|
if (result.status !== 0) {
|
|
434
519
|
fail(
|
|
435
520
|
`${scenario.kit} governed create failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
|
|
@@ -437,8 +522,16 @@ function smokeCreateAgentFrameworkKits() {
|
|
|
437
522
|
}
|
|
438
523
|
assertGeneratedProject(path.join(workspacePath, scenario.name), scenario.expectedFiles);
|
|
439
524
|
}
|
|
525
|
+
const admittedCreates = scenarios.filter((scenario) => scenario.expectCreate);
|
|
440
526
|
const ownershipRoot = path.join(workspacePath, '.workspai', 'agent-frameworks', 'ownership');
|
|
441
|
-
|
|
527
|
+
const recordedOwnership = fs.existsSync(ownershipRoot);
|
|
528
|
+
if (admittedCreates.length === 0) {
|
|
529
|
+
if (recordedOwnership) {
|
|
530
|
+
fail('agent kit smoke recorded ownership receipts without a release-admitted create');
|
|
531
|
+
}
|
|
532
|
+
} else if (!recordedOwnership) {
|
|
533
|
+
fail('agent kit smoke did not record ownership receipts');
|
|
534
|
+
}
|
|
442
535
|
} finally {
|
|
443
536
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
444
537
|
}
|
|
@@ -626,10 +719,112 @@ for (const relativePath of [
|
|
|
626
719
|
assertFile(relativePath);
|
|
627
720
|
}
|
|
628
721
|
|
|
722
|
+
function smokeCreateOpenRouterGatewayKits() {
|
|
723
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'workspai-gateway-kit-smoke-'));
|
|
724
|
+
const workspaceName = 'gateway-kit-workspace';
|
|
725
|
+
const workspacePath = path.join(tempDir, workspaceName);
|
|
726
|
+
const createWorkspace = spawnSync(
|
|
727
|
+
process.execPath,
|
|
728
|
+
[
|
|
729
|
+
cliPath,
|
|
730
|
+
'create',
|
|
731
|
+
'workspace',
|
|
732
|
+
workspaceName,
|
|
733
|
+
'--output',
|
|
734
|
+
tempDir,
|
|
735
|
+
'--profile',
|
|
736
|
+
'minimal',
|
|
737
|
+
'--skip-python-engine',
|
|
738
|
+
'--skip-git',
|
|
739
|
+
'--yes',
|
|
740
|
+
],
|
|
741
|
+
{ cwd: tempDir, encoding: 'utf8', env: cliEnv(), stdio: ['ignore', 'pipe', 'pipe'] }
|
|
742
|
+
);
|
|
743
|
+
if (createWorkspace.status !== 0) {
|
|
744
|
+
fail(
|
|
745
|
+
`gateway kit workspace creation failed with exit ${createWorkspace.status}\n${createWorkspace.stdout}\n${createWorkspace.stderr}`
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const scenarios = [
|
|
750
|
+
{
|
|
751
|
+
kit: 'gateway.openrouter.typescript',
|
|
752
|
+
name: 'openrouter-ts-gateway',
|
|
753
|
+
expectedFiles: [
|
|
754
|
+
'README.md',
|
|
755
|
+
'.env.example',
|
|
756
|
+
'.gitignore',
|
|
757
|
+
'gateway.policy.json',
|
|
758
|
+
'package.json',
|
|
759
|
+
'tsconfig.json',
|
|
760
|
+
'src/port.ts',
|
|
761
|
+
'src/config.ts',
|
|
762
|
+
'src/openrouter-gateway.ts',
|
|
763
|
+
'src/main.ts',
|
|
764
|
+
'tests/gateway.test.ts',
|
|
765
|
+
'.workspai/project.json',
|
|
766
|
+
],
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
kit: 'gateway.openrouter.python',
|
|
770
|
+
name: 'openrouter-py-gateway',
|
|
771
|
+
expectedFiles: [
|
|
772
|
+
'README.md',
|
|
773
|
+
'.env.example',
|
|
774
|
+
'.gitignore',
|
|
775
|
+
'gateway.policy.json',
|
|
776
|
+
'pyproject.toml',
|
|
777
|
+
'main.py',
|
|
778
|
+
'src/model_gateway/port.py',
|
|
779
|
+
'src/model_gateway/config.py',
|
|
780
|
+
'src/model_gateway/gateway.py',
|
|
781
|
+
'src/model_gateway/main.py',
|
|
782
|
+
'tests/test_gateway.py',
|
|
783
|
+
'.workspai/project.json',
|
|
784
|
+
],
|
|
785
|
+
},
|
|
786
|
+
];
|
|
787
|
+
try {
|
|
788
|
+
for (const scenario of scenarios) {
|
|
789
|
+
const result = spawnSync(
|
|
790
|
+
process.execPath,
|
|
791
|
+
[cliPath, 'create', 'project', scenario.kit, scenario.name, '--skip-git', '--yes'],
|
|
792
|
+
{
|
|
793
|
+
cwd: workspacePath,
|
|
794
|
+
encoding: 'utf8',
|
|
795
|
+
env: cliEnv(),
|
|
796
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
if (result.status !== 0) {
|
|
800
|
+
fail(
|
|
801
|
+
`${scenario.kit} create failed with exit ${result.status}\n${result.stdout}\n${result.stderr}`
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
const combined = `${result.stdout}\n${result.stderr}`;
|
|
805
|
+
if (/openrouter\.ai|chat\.completions|Authorization: Bearer/i.test(combined)) {
|
|
806
|
+
fail(`${scenario.kit} create output looks like a live model call\n${combined}`);
|
|
807
|
+
}
|
|
808
|
+
assertGeneratedProject(path.join(workspacePath, scenario.name), scenario.expectedFiles);
|
|
809
|
+
const envExample = fs.readFileSync(
|
|
810
|
+
path.join(workspacePath, scenario.name, '.env.example'),
|
|
811
|
+
'utf8'
|
|
812
|
+
);
|
|
813
|
+
if (/sk-or-[A-Za-z0-9]/.test(envExample) || /OPENROUTER_API_KEY=.+/.test(envExample)) {
|
|
814
|
+
fail(`${scenario.kit} .env.example must not contain a credential value`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
log(`verified ${scenarios.length} model gateway create scenarios`);
|
|
818
|
+
} finally {
|
|
819
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
629
823
|
assertPackContents();
|
|
630
824
|
assertCliContracts();
|
|
631
825
|
smokeCreateNpmBackedKits();
|
|
632
826
|
smokeCreateAgentFrameworkKits();
|
|
827
|
+
smokeCreateOpenRouterGatewayKits();
|
|
633
828
|
smokeCreateOfflineFallbackKits();
|
|
634
829
|
|
|
635
830
|
log('enterprise package smoke passed');
|
package/dist/analyze-6UEBC5OJ.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{b as printAnalyzeReport,a as runAnalyze}from'./chunk-K52IQX3J.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{b as AUTOPILOT_RELEASE_ALIAS_FILENAME,a as AUTOPILOT_RELEASE_LAST_RUN_FILENAME,c as runAutopilotRelease}from'./chunk-EP7SUMAX.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{b as runDoctorCapabilities}from'./chunk-JKAAKE4Z.js';
|