@lerianstudio/matcher-mcp 5.0.0-beta.8 → 5.0.0-beta.81
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 +28 -13
- package/dist/auth/request-token.js +11 -69
- package/dist/auth/request-token.js.map +1 -1
- package/dist/config.js +6 -21
- package/dist/config.js.map +1 -1
- package/dist/copilot/agent.js +5 -9
- package/dist/copilot/agent.js.map +1 -1
- package/dist/copilot/provider-anthropic.js +75 -23
- package/dist/copilot/provider-anthropic.js.map +1 -1
- package/dist/copilot/provider-openrouter.js +5 -18
- package/dist/copilot/provider-openrouter.js.map +1 -1
- package/dist/copilot/provider-shared.js +11 -0
- package/dist/copilot/provider-shared.js.map +1 -1
- package/dist/copilot/speech-provider.js +84 -0
- package/dist/copilot/speech-provider.js.map +1 -0
- package/dist/copilot/sse.js +5 -0
- package/dist/copilot/sse.js.map +1 -1
- package/dist/copilot/tools.js +14 -65
- package/dist/copilot/tools.js.map +1 -1
- package/dist/copilot/transcribe-handler.js +8 -93
- package/dist/copilot/transcribe-handler.js.map +1 -1
- package/dist/copilot/turn-request.js +76 -0
- package/dist/copilot/turn-request.js.map +1 -0
- package/dist/copilot/turns-handler.js +11 -102
- package/dist/copilot/turns-handler.js.map +1 -1
- package/dist/matcher/client.js +14 -0
- package/dist/matcher/client.js.map +1 -1
- package/dist/matcher/idempotency.js +94 -0
- package/dist/matcher/idempotency.js.map +1 -0
- package/dist/observability/otel.js +7 -29
- package/dist/observability/otel.js.map +1 -1
- package/dist/server.js +12 -81
- package/dist/server.js.map +1 -1
- package/dist/spec/curated-operations.js +111 -95
- package/dist/spec/curated-operations.js.map +1 -1
- package/dist/spec/enum-policy.js +21 -26
- package/dist/spec/enum-policy.js.map +1 -1
- package/dist/spec/openapi.yaml +841 -56
- package/dist/spec/schema-parity.js +23 -28
- package/dist/spec/schema-parity.js.map +1 -1
- package/dist/tools/context/create.js +3 -2
- package/dist/tools/context/create.js.map +1 -1
- package/dist/tools/context/index.js +137 -17
- package/dist/tools/context/index.js.map +1 -1
- package/dist/tools/context/list.js +9 -35
- package/dist/tools/context/list.js.map +1 -1
- package/dist/tools/context/setup-progress.js +3 -2
- package/dist/tools/context/setup-progress.js.map +1 -1
- package/dist/tools/context/shared.js +7 -48
- package/dist/tools/context/shared.js.map +1 -1
- package/dist/tools/context/update.js +5 -5
- package/dist/tools/context/update.js.map +1 -1
- package/dist/tools/curated-tool.js +39 -0
- package/dist/tools/curated-tool.js.map +1 -0
- package/dist/tools/dashboard/index.js +124 -19
- package/dist/tools/dashboard/index.js.map +1 -1
- package/dist/tools/dashboard/shared.js +9 -68
- package/dist/tools/dashboard/shared.js.map +1 -1
- package/dist/tools/dispute/close.js +5 -5
- package/dist/tools/dispute/close.js.map +1 -1
- package/dist/tools/dispute/index.js +34 -6
- package/dist/tools/dispute/index.js.map +1 -1
- package/dist/tools/dispute/list.js +18 -47
- package/dist/tools/dispute/list.js.map +1 -1
- package/dist/tools/dispute/shared.js +4 -43
- package/dist/tools/dispute/shared.js.map +1 -1
- package/dist/tools/dispute/submit-evidence.js +5 -5
- package/dist/tools/dispute/submit-evidence.js.map +1 -1
- package/dist/tools/exception/add-comment.js +3 -2
- package/dist/tools/exception/add-comment.js.map +1 -1
- package/dist/tools/exception/adjust-entry.js +5 -5
- package/dist/tools/exception/adjust-entry.js.map +1 -1
- package/dist/tools/exception/bulk-assign.js +3 -2
- package/dist/tools/exception/bulk-assign.js.map +1 -1
- package/dist/tools/exception/bulk-dispatch.js +12 -4
- package/dist/tools/exception/bulk-dispatch.js.map +1 -1
- package/dist/tools/exception/bulk-resolve.js +3 -2
- package/dist/tools/exception/bulk-resolve.js.map +1 -1
- package/dist/tools/exception/dispatch.js +13 -5
- package/dist/tools/exception/dispatch.js.map +1 -1
- package/dist/tools/exception/force-match.js +3 -2
- package/dist/tools/exception/force-match.js.map +1 -1
- package/dist/tools/exception/history.js +8 -24
- package/dist/tools/exception/history.js.map +1 -1
- package/dist/tools/exception/index.js +88 -18
- package/dist/tools/exception/index.js.map +1 -1
- package/dist/tools/exception/list.js +14 -57
- package/dist/tools/exception/list.js.map +1 -1
- package/dist/tools/exception/open-dispute.js +3 -2
- package/dist/tools/exception/open-dispute.js.map +1 -1
- package/dist/tools/exception/shared.js +10 -46
- package/dist/tools/exception/shared.js.map +1 -1
- package/dist/tools/fee-rule/create.js +5 -5
- package/dist/tools/fee-rule/create.js.map +1 -1
- package/dist/tools/fee-rule/index.js +50 -8
- package/dist/tools/fee-rule/index.js.map +1 -1
- package/dist/tools/fee-rule/list.js +9 -29
- package/dist/tools/fee-rule/list.js.map +1 -1
- package/dist/tools/fee-rule/shared.js +5 -47
- package/dist/tools/fee-rule/shared.js.map +1 -1
- package/dist/tools/fee-rule/update.js +5 -5
- package/dist/tools/fee-rule/update.js.map +1 -1
- package/dist/tools/fee-schedule/create.js +8 -3
- package/dist/tools/fee-schedule/create.js.map +1 -1
- package/dist/tools/fee-schedule/index.js +62 -11
- package/dist/tools/fee-schedule/index.js.map +1 -1
- package/dist/tools/fee-schedule/list.js +8 -24
- package/dist/tools/fee-schedule/list.js.map +1 -1
- package/dist/tools/fee-schedule/shared.js +5 -44
- package/dist/tools/fee-schedule/shared.js.map +1 -1
- package/dist/tools/fee-schedule/simulate.js +5 -5
- package/dist/tools/fee-schedule/simulate.js.map +1 -1
- package/dist/tools/fee-schedule/update.js +5 -5
- package/dist/tools/fee-schedule/update.js.map +1 -1
- package/dist/tools/field-map/create.js +3 -2
- package/dist/tools/field-map/create.js.map +1 -1
- package/dist/tools/field-map/index.js +65 -11
- package/dist/tools/field-map/index.js.map +1 -1
- package/dist/tools/field-map/list.js +9 -29
- package/dist/tools/field-map/list.js.map +1 -1
- package/dist/tools/field-map/shared.js +6 -42
- package/dist/tools/field-map/shared.js.map +1 -1
- package/dist/tools/field-map/update.js +3 -2
- package/dist/tools/field-map/update.js.map +1 -1
- package/dist/tools/generic/invoke.js +16 -39
- package/dist/tools/generic/invoke.js.map +1 -1
- package/dist/tools/ingestion/index.js +100 -12
- package/dist/tools/ingestion/index.js.map +1 -1
- package/dist/tools/ingestion/job-transactions-list.js +10 -40
- package/dist/tools/ingestion/job-transactions-list.js.map +1 -1
- package/dist/tools/ingestion/jobs-list.js +9 -35
- package/dist/tools/ingestion/jobs-list.js.map +1 -1
- package/dist/tools/ingestion/shared.js +4 -41
- package/dist/tools/ingestion/shared.js.map +1 -1
- package/dist/tools/ingestion/transactions-search.js +9 -44
- package/dist/tools/ingestion/transactions-search.js.map +1 -1
- package/dist/tools/ingestion/upload-begin.js +5 -2
- package/dist/tools/ingestion/upload-begin.js.map +1 -1
- package/dist/tools/ingestion/upload.js +3 -2
- package/dist/tools/ingestion/upload.js.map +1 -1
- package/dist/tools/input-fields.js +51 -0
- package/dist/tools/input-fields.js.map +1 -0
- package/dist/tools/match-rule/index.js +130 -13
- package/dist/tools/match-rule/index.js.map +1 -1
- package/dist/tools/match-rule/list.js +9 -33
- package/dist/tools/match-rule/list.js.map +1 -1
- package/dist/tools/match-rule/shared.js +16 -46
- package/dist/tools/match-rule/shared.js.map +1 -1
- package/dist/tools/match-rule/update.js +7 -11
- package/dist/tools/match-rule/update.js.map +1 -1
- package/dist/tools/matching/get.js +5 -5
- package/dist/tools/matching/get.js.map +1 -1
- package/dist/tools/matching/groups.js +6 -14
- package/dist/tools/matching/groups.js.map +1 -1
- package/dist/tools/matching/index.js +77 -5
- package/dist/tools/matching/index.js.map +1 -1
- package/dist/tools/matching/list.js +9 -32
- package/dist/tools/matching/list.js.map +1 -1
- package/dist/tools/matching/shared.js +5 -46
- package/dist/tools/matching/shared.js.map +1 -1
- package/dist/tools/query-handler.js +9 -0
- package/dist/tools/query-handler.js.map +1 -0
- package/dist/tools/report/index.js +260 -30
- package/dist/tools/report/index.js.map +1 -1
- package/dist/tools/report/shared.js +24 -98
- package/dist/tools/report/shared.js.map +1 -1
- package/dist/tools/request-fields.js +17 -0
- package/dist/tools/request-fields.js.map +1 -0
- package/dist/tools/shared-dispatch.js +38 -0
- package/dist/tools/shared-dispatch.js.map +1 -0
- package/dist/tools/source/create.js +146 -23
- package/dist/tools/source/create.js.map +1 -1
- package/dist/tools/source/index.js +101 -13
- package/dist/tools/source/index.js.map +1 -1
- package/dist/tools/source/list.js +9 -32
- package/dist/tools/source/list.js.map +1 -1
- package/dist/tools/source/shared.js +5 -42
- package/dist/tools/source/shared.js.map +1 -1
- package/dist/tools/source/update.js +16 -33
- package/dist/tools/source/update.js.map +1 -1
- package/dist/tools/workspace/usage.js +12 -40
- package/dist/tools/workspace/usage.js.map +1 -1
- package/package.json +4 -4
- package/dist/tools/context/archive.js +0 -37
- package/dist/tools/context/archive.js.map +0 -1
- package/dist/tools/context/get.js +0 -31
- package/dist/tools/context/get.js.map +0 -1
- package/dist/tools/context/next-step.js +0 -99
- package/dist/tools/context/next-step.js.map +0 -1
- package/dist/tools/context/restore.js +0 -34
- package/dist/tools/context/restore.js.map +0 -1
- package/dist/tools/dashboard/aggregates.js +0 -37
- package/dist/tools/dashboard/aggregates.js.map +0 -1
- package/dist/tools/dashboard/cash-impact.js +0 -37
- package/dist/tools/dashboard/cash-impact.js.map +0 -1
- package/dist/tools/dashboard/match-rate.js +0 -37
- package/dist/tools/dashboard/match-rate.js.map +0 -1
- package/dist/tools/dashboard/metrics.js +0 -37
- package/dist/tools/dashboard/metrics.js.map +0 -1
- package/dist/tools/dashboard/sla.js +0 -34
- package/dist/tools/dashboard/sla.js.map +0 -1
- package/dist/tools/dashboard/source-breakdown.js +0 -37
- package/dist/tools/dashboard/source-breakdown.js.map +0 -1
- package/dist/tools/dashboard/volume.js +0 -37
- package/dist/tools/dashboard/volume.js.map +0 -1
- package/dist/tools/dispute/get.js +0 -27
- package/dist/tools/dispute/get.js.map +0 -1
- package/dist/tools/exception/delete-comment.js +0 -40
- package/dist/tools/exception/delete-comment.js.map +0 -1
- package/dist/tools/exception/get.js +0 -34
- package/dist/tools/exception/get.js.map +0 -1
- package/dist/tools/exception/list-comments.js +0 -35
- package/dist/tools/exception/list-comments.js.map +0 -1
- package/dist/tools/fee-rule/delete.js +0 -27
- package/dist/tools/fee-rule/delete.js.map +0 -1
- package/dist/tools/fee-rule/get.js +0 -27
- package/dist/tools/fee-rule/get.js.map +0 -1
- package/dist/tools/fee-schedule/delete.js +0 -32
- package/dist/tools/fee-schedule/delete.js.map +0 -1
- package/dist/tools/fee-schedule/get.js +0 -30
- package/dist/tools/fee-schedule/get.js.map +0 -1
- package/dist/tools/field-map/delete.js +0 -37
- package/dist/tools/field-map/delete.js.map +0 -1
- package/dist/tools/field-map/get.js +0 -43
- package/dist/tools/field-map/get.js.map +0 -1
- package/dist/tools/ingestion/job-errors-list.js +0 -45
- package/dist/tools/ingestion/job-errors-list.js.map +0 -1
- package/dist/tools/ingestion/job-get.js +0 -42
- package/dist/tools/ingestion/job-get.js.map +0 -1
- package/dist/tools/ingestion/transaction-ignore.js +0 -51
- package/dist/tools/ingestion/transaction-ignore.js.map +0 -1
- package/dist/tools/match-rule/create.js +0 -67
- package/dist/tools/match-rule/create.js.map +0 -1
- package/dist/tools/match-rule/delete.js +0 -35
- package/dist/tools/match-rule/delete.js.map +0 -1
- package/dist/tools/match-rule/get.js +0 -32
- package/dist/tools/match-rule/get.js.map +0 -1
- package/dist/tools/match-rule/reorder.js +0 -45
- package/dist/tools/match-rule/reorder.js.map +0 -1
- package/dist/tools/matching/start.js +0 -81
- package/dist/tools/matching/start.js.map +0 -1
- package/dist/tools/report/count-exceptions.js +0 -46
- package/dist/tools/report/count-exceptions.js.map +0 -1
- package/dist/tools/report/count-matched.js +0 -47
- package/dist/tools/report/count-matched.js.map +0 -1
- package/dist/tools/report/count-transactions.js +0 -45
- package/dist/tools/report/count-transactions.js.map +0 -1
- package/dist/tools/report/count-unmatched.js +0 -45
- package/dist/tools/report/count-unmatched.js.map +0 -1
- package/dist/tools/report/export-exceptions.js +0 -48
- package/dist/tools/report/export-exceptions.js.map +0 -1
- package/dist/tools/report/export-matched.js +0 -49
- package/dist/tools/report/export-matched.js.map +0 -1
- package/dist/tools/report/export-summary.js +0 -49
- package/dist/tools/report/export-summary.js.map +0 -1
- package/dist/tools/report/export-unmatched.js +0 -49
- package/dist/tools/report/export-unmatched.js.map +0 -1
- package/dist/tools/report/export-variance.js +0 -48
- package/dist/tools/report/export-variance.js.map +0 -1
- package/dist/tools/report/matched.js +0 -48
- package/dist/tools/report/matched.js.map +0 -1
- package/dist/tools/report/summary.js +0 -43
- package/dist/tools/report/summary.js.map +0 -1
- package/dist/tools/report/unmatched.js +0 -48
- package/dist/tools/report/unmatched.js.map +0 -1
- package/dist/tools/report/variance.js +0 -48
- package/dist/tools/report/variance.js.map +0 -1
- package/dist/tools/source/archive.js +0 -46
- package/dist/tools/source/archive.js.map +0 -1
- package/dist/tools/source/get.js +0 -57
- package/dist/tools/source/get.js.map +0 -1
- package/dist/tools/source/restore.js +0 -39
- package/dist/tools/source/restore.js.map +0 -1
package/README.md
CHANGED
|
@@ -44,13 +44,16 @@ as the matcher app, which also pins the embedded OpenAPI spec to the matched
|
|
|
44
44
|
matcher version. The bearer token the relay forwards is never baked into the
|
|
45
45
|
image.
|
|
46
46
|
|
|
47
|
-
It speaks **Streamable HTTP** and binds `MCP_PORT` (default `4019`)
|
|
48
|
-
|
|
47
|
+
It speaks **Streamable HTTP** and binds `MCP_PORT` (default `4019`). The server
|
|
48
|
+
also hosts the optional console copilot and voice routes:
|
|
49
49
|
|
|
50
50
|
| Method | Path | Purpose |
|
|
51
51
|
|--------|------------|--------------------------------------------------|
|
|
52
52
|
| `GET` | `/healthz` | Plain liveness probe. |
|
|
53
53
|
| `POST` | `/mcp` | The Streamable HTTP MCP endpoint clients connect to. |
|
|
54
|
+
| `POST` | `/agent/turns` | Stream an authenticated copilot turn when a provider is configured. |
|
|
55
|
+
| `GET` | `/agent/transcribe` | Report voice-transcription availability for the authenticated caller. |
|
|
56
|
+
| `POST` | `/agent/transcribe` | Transcribe an authenticated voice recording when configured. |
|
|
54
57
|
|
|
55
58
|
Point any Streamable-HTTP MCP client at `POST /mcp` and send the matcher bearer
|
|
56
59
|
token as the `Authorization` header.
|
|
@@ -73,6 +76,9 @@ Three options for `<mcp-url>`:
|
|
|
73
76
|
- **Local matcher dev (repo clone).** `make up` brings the relay up as a compose
|
|
74
77
|
service on `:4019` alongside the rest of the stack (`restart: unless-stopped`,
|
|
75
78
|
so it stays up — no separate process to babysit). Use `http://localhost:4019/mcp`.
|
|
79
|
+
If Matcher runs on the host, stop both Compose `app` and `mcp` first and start
|
|
80
|
+
the host relay with `MATCHER_API_URL=http://localhost:4018`; the Compose relay
|
|
81
|
+
targets the Docker-only name `app:4018`. See [`../docs/development.md`](../docs/development.md).
|
|
76
82
|
- **Run it standalone with `npx`.** `@lerianstudio/matcher-mcp` is a **public**
|
|
77
83
|
package (Apache-2.0) — no registry auth needed. Start the relay (binds `:4019`)
|
|
78
84
|
pointed at your Matcher API:
|
|
@@ -215,7 +221,7 @@ read server-side only, never sent to the browser.
|
|
|
215
221
|
| `OPENROUTER_API_KEY` | _(unset)_ | OpenRouter API key. Required when `COPILOT_PROVIDER=openrouter`. Never logged, never returned. |
|
|
216
222
|
| `COPILOT_MODEL` | _(provider default)_ | Model id passed to the selected provider. Anthropic falls back to its own default when unset; OpenRouter has **no** safe default and requires `COPILOT_MODEL` to be set explicitly (an Anthropic id 404s there), otherwise provider construction raises `CopilotModelRequiredError`. |
|
|
217
223
|
| `COPILOT_MAX_TOOL_ITERATIONS` | `8` | Max read-tool rounds the agent loop runs before forcing a stop. Integer `1..20`. |
|
|
218
|
-
| `COPILOT_MAX_TURN_TOKENS` | `
|
|
224
|
+
| `COPILOT_MAX_TURN_TOKENS` | `400000` | Per-turn ceiling on accumulated input+output; the loop truncates between rounds once crossed. Sized to clear a full 8-round turn at the measured ~39.7k tokens/round (2026-09-08), so `COPILOT_MAX_TOOL_ITERATIONS` is what stops a turn. Not a reservation and not a context-window limit — it is compared against usage already billed, so raising it costs nothing on a turn that ends normally. |
|
|
219
225
|
| `COPILOT_RATE_LIMIT_PER_MIN` | `60` | Per-tenant token-bucket refill rate (turns/min). Per-tenant-overridable. |
|
|
220
226
|
| `COPILOT_RATE_LIMIT_BURST` | `20` | Per-tenant token-bucket burst capacity. Per-tenant-overridable. |
|
|
221
227
|
| `COPILOT_TENANT_CONFIG_PATH` | _(unset)_ | Path to a JSON file mapping `tenantId → { provider, model?, apiKey, maxTurnTokens?, rateLimitPerMin?, rateLimitBurst? }` for per-tenant provider/key overrides. Unset = one global config (BYOC single-tenant). |
|
|
@@ -264,13 +270,14 @@ full embedded OpenAPI spec.
|
|
|
264
270
|
| `fee_schedule_*` | Manage fee schedules — create, list, get, update, delete, and simulate. |
|
|
265
271
|
| `fee_rule_*` | Manage fee rules attached to schedules — create, list, get, update, delete. |
|
|
266
272
|
| `match_rule_*` | Manage a context's match rules — create, list, get, update, delete, reorder. |
|
|
267
|
-
| `context_*` | Manage reconciliation contexts — create, list, get, update,
|
|
268
|
-
| `source_*` | Manage a context's data sources — create, list, get, update,
|
|
273
|
+
| `context_*` | Manage reconciliation contexts — create, list, get, update, archive, restore, setup progress, and next-step guidance. |
|
|
274
|
+
| `source_*` | Manage a context's data sources — create, list, get, update, archive, and restore. |
|
|
275
|
+
| `field_map_*` | Manage field maps — create, list by context, get by source, update, and delete. |
|
|
269
276
|
| `match_run_*` | Drive reconciliation runs — start a run, list runs, get a run, inspect match groups. |
|
|
270
277
|
| `exception_*` | Work reconciliation exceptions — list/get, history and comments (list/add/delete), per-exception action verbs (dispatch, open-dispute, force-match, adjust-entry), and cross-exception bulk actions (assign/resolve/dispatch). |
|
|
271
278
|
| `dispute_*` | Manage the dispute lifecycle — list, get, close, submit evidence. |
|
|
272
|
-
| `ingestion_*` | Inspect a context's import lifecycle — list jobs, get a job, list a job's per-row errors and transactions, search transactions, ignore a transaction
|
|
273
|
-
| `dashboard_*` | Read
|
|
279
|
+
| `ingestion_*` | Inspect a context's import lifecycle — list jobs, get a job, list a job's per-row errors and transactions, search transactions, ignore a transaction, and upload files through `ingestion_upload` or `ingestion_upload_begin`. |
|
|
280
|
+
| `dashboard_*` | Read combined aggregates and focused slices (cash-impact, match-rate, metrics, SLA, source-breakdown, volume). The console uses the aggregate for volume, match rate and SLA, plus separate metrics, source-breakdown and cash-impact queries. Only standalone volume, match-rate and SLA reads have no console consumer. |
|
|
274
281
|
| `report_*` | Pull a context's reports — paginated matched/unmatched/variance reads, the summary read, four counts (exceptions/matched/unmatched/transactions), and five base64 exports (exceptions/matched/summary/unmatched/variance). |
|
|
275
282
|
| `workspace_usage` | Read the caller's own commercial state and free-tier consumption — plan, billing status, both trial axes (days remaining, matched lines against the cap), the expiry verdict, and the derived percentage consumed. Takes no arguments; the workspace comes from the relayed credential. |
|
|
276
283
|
|
|
@@ -288,11 +295,16 @@ HTTP client and a single token relay, so both surfaces map matcher errors
|
|
|
288
295
|
|
|
289
296
|
### Intentionally not curated
|
|
290
297
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
298
|
+
`uploadFile` has curated replacements. Use `ingestion_upload` for a small
|
|
299
|
+
base64-in-JSON payload or `ingestion_upload_begin` for a real local file; the
|
|
300
|
+
relay rebuilds or brokers the multipart request. `matcher_invoke` cannot build
|
|
301
|
+
that binary body and points callers to the curated tools.
|
|
302
|
+
|
|
303
|
+
`extractDocument` accepts a raw document body and has no MCP path today; call
|
|
304
|
+
the Matcher HTTP API directly for that operation. Inbound callback and webhook
|
|
305
|
+
receivers (`processCallback`, aggregator webhooks, and hub events) stay
|
|
306
|
+
generic-only because they are machine- or hub-initiated deliveries rather than
|
|
307
|
+
operator actions.
|
|
296
308
|
|
|
297
309
|
## Project layout
|
|
298
310
|
|
|
@@ -309,7 +321,7 @@ mcp/
|
|
|
309
321
|
└── src/
|
|
310
322
|
├── server.ts # entry point: builds the per-request server, wires tools + telemetry
|
|
311
323
|
├── config.ts # frozen, fail-loud bootstrap config
|
|
312
|
-
├── transport/ #
|
|
324
|
+
├── transport/ # HTTP routing for /healthz, /mcp, /agent/turns and /agent/transcribe
|
|
313
325
|
├── auth/ # request-scoped fail-closed bearer-token relay
|
|
314
326
|
├── matcher/ # Matcher HTTP client
|
|
315
327
|
├── observability/ # OpenTelemetry init + token-free tool instrumentation
|
|
@@ -330,6 +342,9 @@ pnpm test # run vitest
|
|
|
330
342
|
pnpm dev # run with --watch
|
|
331
343
|
```
|
|
332
344
|
|
|
345
|
+
For the Compose and host-process topologies, including the `:4018`/`:4019`
|
|
346
|
+
proxy variables used by the UI, see [`../docs/development.md`](../docs/development.md).
|
|
347
|
+
|
|
333
348
|
## Toolchain
|
|
334
349
|
|
|
335
350
|
Mirrors the `ui/` sub-project: **pnpm** (`pnpm@11.5.2`), Node `>=22`, ESLint flat
|
|
@@ -1,45 +1,16 @@
|
|
|
1
|
-
// Request-scoped
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// owns that contract:
|
|
6
|
-
//
|
|
7
|
-
// - `runWithBearerToken(token, fn)` seeds an AsyncLocalStorage store at the
|
|
8
|
-
// HTTP boundary (transport/http.ts) so handlers can recover the token even
|
|
9
|
-
// when the SDK does not thread request headers through `extra`.
|
|
10
|
-
// - `getRequestBearerToken(extra?)` returns the current caller's token,
|
|
11
|
-
// preferring the SDK-native `extra.requestInfo.headers.authorization` when
|
|
12
|
-
// present and falling back to the ALS store seeded at the boundary.
|
|
13
|
-
// - `requireMatcherClient(extra?)` is the single chokepoint tools call: it
|
|
14
|
-
// reads the token, throws `UnauthenticatedError` when it is missing / empty
|
|
15
|
-
// / not a Bearer credential, and otherwise builds a per-request
|
|
16
|
-
// `MatcherClient` from it.
|
|
17
|
-
//
|
|
18
|
-
// Security invariants (asserted by tests):
|
|
19
|
-
// - The token is NEVER logged and NEVER placed in an error message.
|
|
20
|
-
// - The tenant id MAY be decoded from the relayed JWT (getRequestTenantId),
|
|
21
|
-
// but ONLY unverified and KEY-ONLY: used solely to SCOPE config, limits, and
|
|
22
|
-
// telemetry to an organization, NEVER as an authorization input. Matcher
|
|
23
|
-
// still owns enforcement via the verbatim relayed token, so the tenant
|
|
24
|
-
// third rail stays intact (the decode is not trusted for authz). The token
|
|
25
|
-
// and its decoded claims are never logged.
|
|
1
|
+
// Request-scoped caller-token relay; data tools fail closed without credentials.
|
|
2
|
+
// SDK request headers take precedence over the transport's AsyncLocalStorage.
|
|
3
|
+
// Never log tokens or claims. Unverified tenant claims scope config, limits and
|
|
4
|
+
// telemetry only; Matcher authorizes using the verbatim relayed bearer token.
|
|
26
5
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
27
6
|
import { loadConfig } from '../config.js';
|
|
28
7
|
import { createMatcherClient } from '../matcher/client.js';
|
|
29
8
|
const authStorage = new AsyncLocalStorage();
|
|
30
|
-
/**
|
|
31
|
-
* Operator-facing remediation text shown when the caller did not relay a usable
|
|
32
|
-
* bearer token. It deliberately contains no token material and no internal
|
|
33
|
-
* detail — just what the operator must do to fix their connection.
|
|
34
|
-
*/
|
|
9
|
+
/** Credential remediation without token material or internal details. */
|
|
35
10
|
export const UNAUTHENTICATED_REMEDIATION = 'No matcher credential was provided. Configure your MCP client to send an ' +
|
|
36
11
|
'`Authorization: Bearer <your-matcher-jwt>` header on each request, then ' +
|
|
37
12
|
'retry. This server holds no credentials of its own and relays yours verbatim.';
|
|
38
|
-
/**
|
|
39
|
-
* Thrown when a tool requires the caller's matcher credential but none was
|
|
40
|
-
* relayed (missing, empty, or not a Bearer credential). Carries only the
|
|
41
|
-
* operator remediation text — never any token material.
|
|
42
|
-
*/
|
|
13
|
+
/** Missing or unusable caller credential; contains remediation, never the token. */
|
|
43
14
|
export class UnauthenticatedError extends Error {
|
|
44
15
|
constructor(message = UNAUTHENTICATED_REMEDIATION) {
|
|
45
16
|
super(message);
|
|
@@ -84,17 +55,7 @@ function parseBearer(authorization) {
|
|
|
84
55
|
const token = match[1]?.trim();
|
|
85
56
|
return token && token.length > 0 ? token : undefined;
|
|
86
57
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Resolve the current caller's bearer token, request-scoped.
|
|
89
|
-
*
|
|
90
|
-
* Resolution order:
|
|
91
|
-
* 1. SDK-native `extra.requestInfo.headers.authorization`, when the handler
|
|
92
|
-
* was given an `extra` carrying request headers.
|
|
93
|
-
* 2. The ALS store seeded by `runWithBearerToken` at the HTTP boundary.
|
|
94
|
-
*
|
|
95
|
-
* Returns `undefined` when no usable Bearer credential is present (missing,
|
|
96
|
-
* empty, or non-Bearer scheme) — callers fail closed on that.
|
|
97
|
-
*/
|
|
58
|
+
/** Prefer a usable SDK bearer, then transport ALS; absent credentials fail closed. */
|
|
98
59
|
export function getRequestBearerToken(extra) {
|
|
99
60
|
const fromExtra = parseBearer(authorizationFromExtra(extra));
|
|
100
61
|
if (fromExtra) {
|
|
@@ -103,20 +64,9 @@ export function getRequestBearerToken(extra) {
|
|
|
103
64
|
return parseBearer(authStorage.getStore()?.authorization);
|
|
104
65
|
}
|
|
105
66
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* via the verbatim relayed token, so the tenant third rail stays intact even
|
|
110
|
-
* though this reads the claim.
|
|
111
|
-
*
|
|
112
|
-
* Reads the same request-scoped bearer `getRequestBearerToken` resolves, splits
|
|
113
|
-
* the JWT, base64url-decodes the payload segment (Node stdlib `Buffer` — NO JWT
|
|
114
|
-
* library), and reads the tenant claim. Matches the Go/lib-auth extraction order
|
|
115
|
-
* (`claimString(claims, "tenant_id", "tenantId")`): prefers `tenant_id`, then
|
|
116
|
-
* `tenantId`. Returns `undefined` on ANY malformed/absent token or a
|
|
117
|
-
* missing/non-string/empty claim, and NEVER throws — a decode failure fails open
|
|
118
|
-
* to the global-config path rather than breaking the turn. The token and its
|
|
119
|
-
* claims are never logged.
|
|
67
|
+
* Unverified tenant key for config, limits and telemetry — NEVER authorization.
|
|
68
|
+
* Prefers tenant_id to tenantId. Malformed/absent claims yield undefined and
|
|
69
|
+
* select global config; neither the token nor its claims may enter logs.
|
|
120
70
|
*/
|
|
121
71
|
export function getRequestTenantId(extra) {
|
|
122
72
|
const token = getRequestBearerToken(extra);
|
|
@@ -146,15 +96,7 @@ export function getRequestTenantId(extra) {
|
|
|
146
96
|
return undefined;
|
|
147
97
|
}
|
|
148
98
|
}
|
|
149
|
-
/**
|
|
150
|
-
* The single chokepoint every matcher-touching tool calls. Reads the caller's
|
|
151
|
-
* request-scoped token and, when present, returns a `MatcherClient` bound to it.
|
|
152
|
-
* Fails closed with `UnauthenticatedError` when the token is absent / empty /
|
|
153
|
-
* not a Bearer credential.
|
|
154
|
-
*
|
|
155
|
-
* `config` is injectable for tests; production callers pass nothing and get the
|
|
156
|
-
* process config.
|
|
157
|
-
*/
|
|
99
|
+
/** Build a caller-bound client or fail closed; config is injectable for tests. */
|
|
158
100
|
export function requireMatcherClient(extra, config = loadConfig()) {
|
|
159
101
|
const token = getRequestBearerToken(extra);
|
|
160
102
|
if (!token) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-token.js","sourceRoot":"","sources":["../../src/auth/request-token.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"request-token.js","sourceRoot":"","sources":["../../src/auth/request-token.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Values are read from the environment once and frozen into a typed object.
|
|
4
|
-
// Defaults are chosen to avoid collisions with matcher dev (matcher runs on
|
|
5
|
-
// 4018; this server defaults to 4019). The matcher base URL is surfaced here
|
|
6
|
-
// so the HTTP client (task 1.3.1) and the generic invoke / curated tools
|
|
7
|
-
// consume a single source of truth instead of reading process.env directly.
|
|
1
|
+
// Environment configuration is loaded once and frozen for all relay consumers.
|
|
8
2
|
import { loadTenantConfig } from './copilot/tenant-config.js';
|
|
9
3
|
const DEFAULT_PORT = 4019;
|
|
10
4
|
const DEFAULT_MATCHER_API_URL = 'http://localhost:4018';
|
|
@@ -13,7 +7,7 @@ const DEFAULT_MAX_BODY_BYTES = 1_048_576; // 1 MiB
|
|
|
13
7
|
const DEFAULT_OTEL_SERVICE_NAME = 'matcher-mcp';
|
|
14
8
|
const DEFAULT_COPILOT_PROVIDER = 'anthropic';
|
|
15
9
|
const DEFAULT_COPILOT_MAX_TOOL_ITERATIONS = 8;
|
|
16
|
-
const DEFAULT_COPILOT_MAX_TURN_TOKENS =
|
|
10
|
+
const DEFAULT_COPILOT_MAX_TURN_TOKENS = 400_000;
|
|
17
11
|
const DEFAULT_COPILOT_RATE_LIMIT_PER_MIN = 60;
|
|
18
12
|
const DEFAULT_COPILOT_RATE_LIMIT_BURST = 20;
|
|
19
13
|
const DEFAULT_SPEECH_TRANSCRIPTION_REGION = 'sa-east-1';
|
|
@@ -33,9 +27,7 @@ function parsePort(raw, fallback) {
|
|
|
33
27
|
return value;
|
|
34
28
|
}
|
|
35
29
|
/**
|
|
36
|
-
*
|
|
37
|
-
* default when unset. An explicitly-set but invalid value is a misconfiguration
|
|
38
|
-
* and throws, rather than silently degrading to the default (fail-loud at boot).
|
|
30
|
+
* Default an unset timeout; reject explicit invalid millisecond values at boot.
|
|
39
31
|
*/
|
|
40
32
|
function parseTimeoutMs(raw, fallback) {
|
|
41
33
|
if (raw === undefined || raw === '') {
|
|
@@ -48,9 +40,7 @@ function parseTimeoutMs(raw, fallback) {
|
|
|
48
40
|
return value;
|
|
49
41
|
}
|
|
50
42
|
/**
|
|
51
|
-
*
|
|
52
|
-
* when unset. An explicitly-set but invalid value is a misconfiguration and
|
|
53
|
-
* throws, rather than silently degrading to the default (fail-loud at boot).
|
|
43
|
+
* Default an unset body limit; reject explicit invalid byte counts at boot.
|
|
54
44
|
*/
|
|
55
45
|
function parseMaxBodyBytes(raw, fallback) {
|
|
56
46
|
if (raw === undefined || raw === '') {
|
|
@@ -82,10 +72,7 @@ function parseBool(raw, fallback, key) {
|
|
|
82
72
|
throw new Error(`invalid ${key}: ${raw} (expected one of true, false, 1, 0)`);
|
|
83
73
|
}
|
|
84
74
|
/**
|
|
85
|
-
*
|
|
86
|
-
* when unset. Trimmed + case-insensitive. An explicitly-set but unrecognized
|
|
87
|
-
* value is a misconfiguration and throws, rather than silently coercing to a
|
|
88
|
-
* default (fail-loud at boot), mirroring parseBool.
|
|
75
|
+
* Default an unset provider; trim and case-fold explicit names, rejecting unknowns.
|
|
89
76
|
*/
|
|
90
77
|
function parseCopilotProvider(raw, fallback) {
|
|
91
78
|
if (raw === undefined || raw === '') {
|
|
@@ -113,9 +100,7 @@ function parseMaxToolIterations(raw, fallback) {
|
|
|
113
100
|
return value;
|
|
114
101
|
}
|
|
115
102
|
/**
|
|
116
|
-
*
|
|
117
|
-
* when unset. An explicitly-set non-positive or non-integer value is a
|
|
118
|
-
* misconfiguration and throws (fail-loud at boot), mirroring parseMaxBodyBytes.
|
|
103
|
+
* Default an unset integer; reject explicit non-positive or fractional values.
|
|
119
104
|
*/
|
|
120
105
|
function parsePositiveInt(raw, fallback, key) {
|
|
121
106
|
if (raw === undefined || raw === '') {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/copilot/agent.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// module — the request-scoped executor resolves it from the ALS store.
|
|
15
15
|
import { instrumentCopilotTool, instrumentCopilotTurn, instrumentProviderStream, recordCopilotTokens, } from '../observability/otel.js';
|
|
16
16
|
import { InvokeError, Invoker } from '../tools/generic/invoke.js';
|
|
17
|
+
import { finishWithError } from './sse.js';
|
|
17
18
|
import { executeReadTool, WRITE_ALLOWLIST } from './tools.js';
|
|
18
19
|
/**
|
|
19
20
|
* Sum a round's input+output tokens, failing open: `undefined` usage (a provider
|
|
@@ -66,8 +67,7 @@ function emitProposal(call, index, sink) {
|
|
|
66
67
|
// is latent; but a future one would execute WITHOUT it (a silently wrong
|
|
67
68
|
// write). Refuse loudly instead of minting a lossy proposal.
|
|
68
69
|
if (request.query !== undefined && Object.keys(request.query).length > 0) {
|
|
69
|
-
sink
|
|
70
|
-
sink.done('end');
|
|
70
|
+
finishWithError(sink, 'proposal_invalid', 'write proposals cannot carry query parameters');
|
|
71
71
|
return 'end';
|
|
72
72
|
}
|
|
73
73
|
const op = index.operations.get(call.name);
|
|
@@ -91,8 +91,7 @@ function emitProposal(call, index, sink) {
|
|
|
91
91
|
}
|
|
92
92
|
catch (err) {
|
|
93
93
|
const detail = err instanceof InvokeError ? err.message : 'failed to prepare the proposal';
|
|
94
|
-
sink
|
|
95
|
-
sink.done('end');
|
|
94
|
+
finishWithError(sink, 'proposal_invalid', detail);
|
|
96
95
|
return 'end';
|
|
97
96
|
}
|
|
98
97
|
}
|
|
@@ -145,9 +144,7 @@ export async function runAgentTurn(opts) {
|
|
|
145
144
|
// renders as an error, mirroring the iteration-cap path.
|
|
146
145
|
if (maxTurnTokens !== undefined && totalTokens >= maxTurnTokens) {
|
|
147
146
|
setStop('token_limit');
|
|
148
|
-
sink
|
|
149
|
-
sink.done('end');
|
|
150
|
-
return;
|
|
147
|
+
return finishWithError(sink, 'turn_token_limit', `reached the per-turn token limit (${maxTurnTokens})`);
|
|
151
148
|
}
|
|
152
149
|
// ponytail: sequential tool exec; parallelize only if a turn routinely
|
|
153
150
|
// fans out many reads. Matcher reads are cheap, so ordering keeps the SSE
|
|
@@ -174,8 +171,7 @@ export async function runAgentTurn(opts) {
|
|
|
174
171
|
}
|
|
175
172
|
// Ran `maxIterations` tool rounds and the model still wants more: hard stop.
|
|
176
173
|
setStop('iteration_limit');
|
|
177
|
-
sink
|
|
178
|
-
sink.done('end');
|
|
174
|
+
finishWithError(sink, 'tool_iteration_limit', `reached the tool-call limit (${maxIterations})`);
|
|
179
175
|
});
|
|
180
176
|
}
|
|
181
177
|
//# sourceMappingURL=agent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/copilot/agent.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,gFAAgF;AAChF,gFAAgF;AAChF,iFAAiF;AACjF,yEAAyE;AACzE,0EAA0E;AAC1E,uCAAuC;AACvC,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AAEvE,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/copilot/agent.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,gFAAgF;AAChF,gFAAgF;AAChF,iFAAiF;AACjF,yEAAyE;AACzE,0EAA0E;AAC1E,uCAAuC;AACvC,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AAEvE,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AASjE,OAAO,EAAE,eAAe,EAAgB,MAAM,UAAU,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA+B7D;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAA2B;IAC9C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,CAAA;IACV,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;IACxE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3E,OAAO,KAAK,GAAG,MAAM,CAAA;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAS,YAAY,CACnB,IAAiB,EACjB,KAAqB,EACrB,IAAa;IAEb,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAgD,CAAA;IAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAoD,CAAA;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAA;IAC5B,IAAI,CAAC;QACH,yEAAyE;QACzE,mEAAmE;QACnE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC;YAC1C,WAAW,EAAE,IAAI,CAAC,IAAI;YACtB,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC,CAAC,CAAA;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,yEAAyE;QACzE,6DAA6D;QAC7D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzE,eAAe,CAAC,IAAI,EAAE,kBAAkB,EAAE,+CAA+C,CAAC,CAAA;YAC1F,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC1C,MAAM,OAAO,GACX,EAAE,KAAK,SAAS,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YACvC,CAAC,CAAC,EAAE,CAAC,OAAO;YACZ,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAA;QACtC,MAAM,MAAM,GACV,OAAO,CAAC,IAAI,KAAK,IAAI;YACrB,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ;YAChC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YAC1B,CAAC,CAAE,OAAO,CAAC,IAAgC;YAC3C,CAAC,CAAC,EAAE,CAAA;QACR,IAAI,CAAC,QAAQ,CAAC;YACZ,WAAW,EAAE,IAAI,CAAC,IAAI;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM;YACN,OAAO;SACR,CAAC,CAAA;QACF,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACrB,OAAO,UAAU,CAAA;IACnB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GACV,GAAG,YAAY,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAA;QAC7E,eAAe,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAA;QACjD,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAyB;IAC1D,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,IAAI,CAAA;IAC9E,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,SAAS,CAAA;IACnD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,eAAe,CAAA;IAEvD,MAAM,qBAAqB,CACzB;QACE,QAAQ,EAAE,YAAY;QACtB,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,aAAa;KACd,EACD,KAAK,EAAE,OAAO,EAAE,EAAE;QAChB,IAAI,WAAwC,CAAA;QAC5C,IAAI,WAAW,GAAG,CAAC,CAAA;QAEnB,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,aAAa,EAAE,SAAS,IAAI,CAAC,EAAE,CAAC;YAClE,uEAAuE;YACvE,8EAA8E;YAC9E,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACpB,OAAO,CAAC,SAAS,CAAC,CAAA;gBAClB,OAAM;YACR,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAC3C,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EACrE,GAAG,EAAE,CACH,QAAQ,CAAC,UAAU,CACjB;gBACE,MAAM;gBACN,QAAQ;gBACR,KAAK;gBACL,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtD,EACD,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAC7C,CACJ,CAAA;YAED,wEAAwE;YACxE,0EAA0E;YAC1E,mBAAmB,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;YAC/C,WAAW,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAExC,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;gBAC1B,wEAAwE;gBACxE,gDAAgD;gBAChD,OAAO,CAAC,KAAK,CAAC,CAAA;gBACd,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBAChB,OAAM;YACR,CAAC;YAED,yEAAyE;YACzE,wEAAwE;YACxE,sEAAsE;YACtE,yDAAyD;YACzD,IAAI,aAAa,KAAK,SAAS,IAAI,WAAW,IAAI,aAAa,EAAE,CAAC;gBAChE,OAAO,CAAC,aAAa,CAAC,CAAA;gBACtB,OAAO,eAAe,CAAC,IAAI,EAAE,kBAAkB,EAAE,qCAAqC,aAAa,GAAG,CAAC,CAAA;YACzG,CAAC;YAED,uEAAuE;YACvE,0EAA0E;YAC1E,uCAAuC;YACvC,MAAM,OAAO,GAAoB,EAAE,CAAA;YACnC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAChC,iEAAiE;gBACjE,mEAAmE;gBACnE,oBAAoB;gBACpB,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;oBACxC,OAAM;gBACR,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;gBAC/B,mEAAmE;gBACnE,kEAAkE;gBAClE,MAAM,CAAC,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;gBAChF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;gBACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,2EAA2E;YAC3E,yEAAyE;YACzE,WAAW,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAA;QACpD,CAAC;QAED,6EAA6E;QAC7E,OAAO,CAAC,iBAAiB,CAAC,CAAA;QAC1B,eAAe,CAAC,IAAI,EAAE,sBAAsB,EAAE,gCAAgC,aAAa,GAAG,CAAC,CAAA;IACjG,CAAC,CACF,CAAA;AACH,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// call — nothing persists across turns.
|
|
6
6
|
import Anthropic from '@anthropic-ai/sdk';
|
|
7
7
|
import { CopilotUnconfiguredError } from './provider-factory.js';
|
|
8
|
-
import {
|
|
8
|
+
import { buildTurnResult } from './provider-shared.js';
|
|
9
9
|
// Max tokens the Messages API requires per request. A fixed ceiling is fine for
|
|
10
10
|
// grounded read-only answers.
|
|
11
11
|
// ponytail: fixed cap; make configurable if turns start truncating.
|
|
@@ -21,6 +21,16 @@ const ANTHROPIC_DEFAULT_MODEL = 'claude-opus-4-8';
|
|
|
21
21
|
// ponytail: placeholder name/input is a known ceiling — enrich LLMToolResult
|
|
22
22
|
// with the originating name/input if the model needs to see its prior args.
|
|
23
23
|
const SYNTHETIC_TOOL_USE_NAME = 'tool';
|
|
24
|
+
/**
|
|
25
|
+
* The prompt-cache breakpoint marker, at the default 5-minute TTL.
|
|
26
|
+
*
|
|
27
|
+
* 5m, not 1h: the 1-hour TTL costs 2x on the write instead of 1.25x and only
|
|
28
|
+
* pays off when requests sharing the prefix start more than five minutes
|
|
29
|
+
* apart. Every round inside an agentic turn starts seconds after the last, and
|
|
30
|
+
* a read refreshes the entry's timer for free, so a busy console keeps the
|
|
31
|
+
* 5-minute entry alive indefinitely at the cheaper write price.
|
|
32
|
+
*/
|
|
33
|
+
const CACHE_EPHEMERAL = { type: 'ephemeral' };
|
|
24
34
|
/**
|
|
25
35
|
* Build a provider backed by Anthropic. When `streamFn` is omitted the key is
|
|
26
36
|
* required (its absence throws CopilotUnconfiguredError here, at construction);
|
|
@@ -31,10 +41,31 @@ export function createAnthropicProvider(config, streamFn) {
|
|
|
31
41
|
return {
|
|
32
42
|
async streamTurn(input, handlers) {
|
|
33
43
|
const tools = input.tools.map(toAnthropicTool);
|
|
44
|
+
// Prompt caching, two of the API's four allowed breakpoints.
|
|
45
|
+
//
|
|
46
|
+
// The request renders as tools -> system -> messages, and everything up
|
|
47
|
+
// to the end of `system` is byte-identical on every round of every turn:
|
|
48
|
+
// `buildSystemPrompt` returns a frozen module constant with nothing
|
|
49
|
+
// interpolated into it (the operator's screen context is deliberately a
|
|
50
|
+
// user message, not part of the system tier), and the tool catalogue is
|
|
51
|
+
// memoized over the immutable spec index. That static floor is the whole
|
|
52
|
+
// prize (it dwarfs the conversation), so breakpoint 1 goes on the last
|
|
53
|
+
// (only) system block, which caches the tools ahead of it in the same
|
|
54
|
+
// entry. Nothing had to be moved out of it; it was already stable, just
|
|
55
|
+
// unmarked.
|
|
56
|
+
//
|
|
57
|
+
// Breakpoint 2 is the top-level marker: the API places it on the last
|
|
58
|
+
// cacheable block and walks it forward as the request grows, which is
|
|
59
|
+
// exactly the shape of the tail here: a turn accumulates tool results
|
|
60
|
+
// round over round, and the browser replays the whole conversation on
|
|
61
|
+
// the next POST. A write bills only the delta past the highest cache
|
|
62
|
+
// hit, so this second entry costs the messages delta, never the prefix
|
|
63
|
+
// breakpoint 1 already covers.
|
|
34
64
|
const params = {
|
|
35
65
|
model: config.copilotModel ?? ANTHROPIC_DEFAULT_MODEL,
|
|
36
66
|
max_tokens: ANTHROPIC_MAX_TOKENS,
|
|
37
|
-
system: input.system,
|
|
67
|
+
system: [{ type: 'text', text: input.system, cache_control: CACHE_EPHEMERAL }],
|
|
68
|
+
cache_control: CACHE_EPHEMERAL,
|
|
38
69
|
messages: buildAnthropicMessages(input),
|
|
39
70
|
...(tools.length > 0 ? { tools } : {}),
|
|
40
71
|
};
|
|
@@ -46,13 +77,25 @@ export function createAnthropicProvider(config, streamFn) {
|
|
|
46
77
|
// neither, so the loop meters this round as 0 (fail-open).
|
|
47
78
|
let inputTokens;
|
|
48
79
|
let outputTokens;
|
|
80
|
+
// Prompt-cache halves of the input, tracked separately so `usageFrom`
|
|
81
|
+
// can both fold them into the true prompt size and report them raw. Read
|
|
82
|
+
// off message_start with message_delta (also cumulative, and nullable
|
|
83
|
+
// there) as a refresh, so a stream that only populates them on the delta
|
|
84
|
+
// is still accounted rather than silently metered as an uncached turn.
|
|
85
|
+
let cacheCreationTokens;
|
|
86
|
+
let cacheReadTokens;
|
|
49
87
|
for await (const event of openStream(params)) {
|
|
50
88
|
if (event.type === 'message_start') {
|
|
51
89
|
inputTokens = event.message.usage.input_tokens;
|
|
52
90
|
outputTokens = event.message.usage.output_tokens;
|
|
91
|
+
cacheCreationTokens = event.message.usage.cache_creation_input_tokens ?? undefined;
|
|
92
|
+
cacheReadTokens = event.message.usage.cache_read_input_tokens ?? undefined;
|
|
53
93
|
}
|
|
54
94
|
else if (event.type === 'message_delta') {
|
|
55
95
|
outputTokens = event.usage.output_tokens;
|
|
96
|
+
cacheCreationTokens =
|
|
97
|
+
event.usage.cache_creation_input_tokens ?? cacheCreationTokens;
|
|
98
|
+
cacheReadTokens = event.usage.cache_read_input_tokens ?? cacheReadTokens;
|
|
56
99
|
}
|
|
57
100
|
else if (event.type === 'content_block_start' &&
|
|
58
101
|
event.content_block.type === 'tool_use') {
|
|
@@ -74,22 +117,13 @@ export function createAnthropicProvider(config, streamFn) {
|
|
|
74
117
|
}
|
|
75
118
|
}
|
|
76
119
|
}
|
|
77
|
-
const usage = usageFrom(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// path: capture stop_reason into the done label if operators hit it.
|
|
85
|
-
return { stop: 'end', ...(usage !== undefined ? { usage } : {}) };
|
|
86
|
-
}
|
|
87
|
-
const calls = [...toolBlocks.values()].map((block) => ({
|
|
88
|
-
id: block.id,
|
|
89
|
-
name: block.name,
|
|
90
|
-
input: parseToolInput(block.json),
|
|
91
|
-
}));
|
|
92
|
-
return { stop: 'tool_use', calls, ...(usage !== undefined ? { usage } : {}) };
|
|
120
|
+
const usage = usageFrom({
|
|
121
|
+
inputTokens,
|
|
122
|
+
outputTokens,
|
|
123
|
+
cacheCreationTokens,
|
|
124
|
+
cacheReadTokens,
|
|
125
|
+
});
|
|
126
|
+
return buildTurnResult([...toolBlocks.values()], usage);
|
|
93
127
|
},
|
|
94
128
|
};
|
|
95
129
|
}
|
|
@@ -104,14 +138,32 @@ function defaultAnthropicStream(config) {
|
|
|
104
138
|
}
|
|
105
139
|
/**
|
|
106
140
|
* Build an LLMUsage from the tracked token counts, or `undefined` when the
|
|
107
|
-
* stream reported
|
|
108
|
-
* missing
|
|
141
|
+
* stream reported no usage at all (so the loop meters this round as 0, which
|
|
142
|
+
* is fail-open). A missing field defaults to 0 rather than dropping the whole
|
|
143
|
+
* usage.
|
|
144
|
+
*
|
|
145
|
+
* `inputTokens` is deliberately NOT the API's `input_tokens`. With caching on,
|
|
146
|
+
* that field counts only the uncached remainder. The total prompt is
|
|
147
|
+
* `input_tokens + cache_creation_input_tokens + cache_read_input_tokens`, so
|
|
148
|
+
* the cached halves are added back here. Reporting the remainder instead would
|
|
149
|
+
* make every cached round look ~25k tokens cheaper than it is to the two
|
|
150
|
+
* consumers that read this number: the per-turn ceiling in `runAgentTurn`
|
|
151
|
+
* (which would stop tripping on a runaway) and the copilot token metric (which
|
|
152
|
+
* would under-report the prompt floor by the whole cached prefix). The raw
|
|
153
|
+
* halves ride alongside, unfolded, as the cache-hit evidence.
|
|
109
154
|
*/
|
|
110
|
-
function usageFrom(
|
|
111
|
-
if (inputTokens === undefined && outputTokens === undefined) {
|
|
155
|
+
function usageFrom(raw) {
|
|
156
|
+
if (raw.inputTokens === undefined && raw.outputTokens === undefined) {
|
|
112
157
|
return undefined;
|
|
113
158
|
}
|
|
114
|
-
|
|
159
|
+
const cacheCreationTokens = raw.cacheCreationTokens ?? 0;
|
|
160
|
+
const cacheReadTokens = raw.cacheReadTokens ?? 0;
|
|
161
|
+
return {
|
|
162
|
+
inputTokens: (raw.inputTokens ?? 0) + cacheCreationTokens + cacheReadTokens,
|
|
163
|
+
outputTokens: raw.outputTokens ?? 0,
|
|
164
|
+
cacheCreationTokens,
|
|
165
|
+
cacheReadTokens,
|
|
166
|
+
};
|
|
115
167
|
}
|
|
116
168
|
function toAnthropicTool(def) {
|
|
117
169
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-anthropic.js","sourceRoot":"","sources":["../../src/copilot/provider-anthropic.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,wCAAwC;AAExC,OAAO,SAAS,MAAM,mBAAmB,CAAA;AAGzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"provider-anthropic.js","sourceRoot":"","sources":["../../src/copilot/provider-anthropic.ts"],"names":[],"mappings":"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"}
|