@plumbus/core 0.8.0-beta.5 → 0.8.0-beta.7
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/CHANGELOG.md +60 -0
- package/README.md +6 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/ai/ai/cost-tracker.d.ts +5 -1
- package/dist/ai/ai/model-pricing.d.ts +3 -2
- package/dist/ai/ai-service.d.ts +3 -0
- package/dist/ai/ai-service.d.ts.map +1 -1
- package/dist/ai/ai-service.js +146 -24
- package/dist/ai/ai-service.js.map +1 -1
- package/dist/ai/cost-tracker.d.ts +5 -1
- package/dist/ai/cost-tracker.d.ts.map +1 -1
- package/dist/ai/cost-tracker.js +7 -2
- package/dist/ai/cost-tracker.js.map +1 -1
- package/dist/ai/explainability.d.ts +2 -1
- package/dist/ai/explainability.d.ts.map +1 -1
- package/dist/ai/explainability.js +1 -0
- package/dist/ai/explainability.js.map +1 -1
- package/dist/ai/model-pricing.d.ts +3 -2
- package/dist/ai/model-pricing.d.ts.map +1 -1
- package/dist/ai/model-pricing.js +23 -2
- package/dist/ai/model-pricing.js.map +1 -1
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/ai/provider.js +35 -15
- package/dist/ai/provider.js.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +2 -1
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/generate-openapi-from-zod.d.ts.map +1 -1
- package/dist/cli/commands/generate-openapi-from-zod.js +9 -1
- package/dist/cli/commands/generate-openapi-from-zod.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +3 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +2 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/worker.js +1 -1
- package/dist/cli/commands/worker.js.map +1 -1
- package/dist/cli/discover.d.ts +2 -0
- package/dist/cli/discover.d.ts.map +1 -1
- package/dist/cli/discover.js +19 -2
- package/dist/cli/discover.js.map +1 -1
- package/dist/events/dispatcher.d.ts +9 -0
- package/dist/events/dispatcher.d.ts.map +1 -1
- package/dist/events/dispatcher.js +36 -17
- package/dist/events/dispatcher.js.map +1 -1
- package/dist/events/pipeline-audit.d.ts +14 -0
- package/dist/events/pipeline-audit.d.ts.map +1 -0
- package/dist/events/pipeline-audit.js +29 -0
- package/dist/events/pipeline-audit.js.map +1 -0
- package/dist/events/worker.d.ts +3 -0
- package/dist/events/worker.d.ts.map +1 -1
- package/dist/events/worker.js +13 -11
- package/dist/events/worker.js.map +1 -1
- package/dist/execution/context-factory.d.ts.map +1 -1
- package/dist/execution/context-factory.js +3 -0
- package/dist/execution/context-factory.js.map +1 -1
- package/dist/flows/engine.d.ts.map +1 -1
- package/dist/flows/engine.js +2 -0
- package/dist/flows/engine.js.map +1 -1
- package/dist/runtime/bootstrap.d.ts +3 -1
- package/dist/runtime/bootstrap.d.ts.map +1 -1
- package/dist/runtime/bootstrap.js +19 -4
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/load-extensions.d.ts +2 -1
- package/dist/runtime/load-extensions.d.ts.map +1 -1
- package/dist/runtime/load-extensions.js +8 -1
- package/dist/runtime/load-extensions.js.map +1 -1
- package/dist/runtime/start-worker-pool.d.ts.map +1 -1
- package/dist/runtime/start-worker-pool.js +1 -0
- package/dist/runtime/start-worker-pool.js.map +1 -1
- package/dist/server/bootstrap.d.ts +3 -0
- package/dist/server/bootstrap.d.ts.map +1 -1
- package/dist/server/bootstrap.js +20 -1
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/testing/context.d.ts +2 -0
- package/dist/testing/context.d.ts.map +1 -1
- package/dist/testing/context.js +7 -3
- package/dist/testing/context.js.map +1 -1
- package/dist/types/context.d.ts +15 -1
- package/dist/types/context.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/worker/bootstrap.d.ts.map +1 -1
- package/dist/worker/bootstrap.js +3 -0
- package/dist/worker/bootstrap.js.map +1 -1
- package/instructions/README.md +2 -1
- package/instructions/ai-classification.md +114 -0
- package/instructions/ai.md +28 -1
- package/instructions/peer-dependencies.md +1 -1
- package/package.json +6 -5
- package/dist/ai/__typecheck-fixtures__/legacy-cost-api.d.ts +0 -5
- package/dist/ai/__typecheck-fixtures__/legacy-cost-api.d.ts.map +0 -1
- package/dist/ai/__typecheck-fixtures__/legacy-cost-api.js +0 -15
- package/dist/ai/__typecheck-fixtures__/legacy-cost-api.js.map +0 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# AI classification: provider and model selection
|
|
2
|
+
|
|
3
|
+
Read this when implementing classification, categorization, label selection, or
|
|
4
|
+
TypeSafe/Jev and Laya integration. Requires **@plumbus/core 0.7.4+** (0.8 family: **0.8.0-beta.6+**) for the
|
|
5
|
+
`classify()` provider/model options. Use this recipe inside Plumbus capabilities
|
|
6
|
+
and flows; preserve their access policies and declare `effects.ai: true`.
|
|
7
|
+
|
|
8
|
+
## Choose the operation
|
|
9
|
+
|
|
10
|
+
| Need | Operation |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| Matching labels from a known list, using a generative or decision model | `ctx.ai.classify()` → `string[]` |
|
|
13
|
+
| Typed choices, ordinal scores, probabilities, or mixed questions | `ctx.ai.decide()` → typed answers |
|
|
14
|
+
| Generated text or structured output from a prompt | `ctx.ai.generate()` |
|
|
15
|
+
|
|
16
|
+
Do not call vendor adapters directly for application business logic. Both native
|
|
17
|
+
classification and decisions use core validation, security, budgets, identity,
|
|
18
|
+
cancellation, and accounting. Predictions never replace authorization.
|
|
19
|
+
|
|
20
|
+
## Register the provider
|
|
21
|
+
|
|
22
|
+
Install only the decision provider needed by the app:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm add @plumbus/core@~0.7.4 @plumbus/ai-decision-typesafe@~0.2.2
|
|
26
|
+
# For self-hosted Laya, use @plumbus/ai-decision-laya@~0.2.2 instead.
|
|
27
|
+
# 0.8 beta family: pnpm add @plumbus/core@plumbus-next @plumbus/ai-decision-typesafe@plumbus-next
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Export registration at the server boundary so API and workers share it:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// app/server.ts
|
|
34
|
+
import { createTypeSafeDecisionAdapter } from '@plumbus/ai-decision-typesafe';
|
|
35
|
+
|
|
36
|
+
export const decisions = {
|
|
37
|
+
providers: {
|
|
38
|
+
typesafe: createTypeSafeDecisionAdapter({
|
|
39
|
+
apiKey: process.env.TYPESAFE_API_KEY ?? '',
|
|
40
|
+
model: 'jev-1.13.0',
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
defaultProvider: 'typesafe',
|
|
44
|
+
};
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For Laya, register `laya: createLayaDecisionAdapter({ baseUrl, apiKey })` using the
|
|
48
|
+
factory from `@plumbus/ai-decision-laya`. Keep credentials and adapter construction
|
|
49
|
+
on the server. Laya requires a separately running service. For programmatic
|
|
50
|
+
bootstrap, pass `decisions` to `createServer()` / `buildWorkerAiService()` or
|
|
51
|
+
`createAIService()`. Decision adapters belong under `decisions.providers`, not the
|
|
52
|
+
text-completion `providers` map. Use distinct names across those two maps.
|
|
53
|
+
|
|
54
|
+
## Select a provider and model per call
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// Inside a capability handler or flow step:
|
|
58
|
+
const labels = await ctx.ai.classify({
|
|
59
|
+
text: input.ticketText,
|
|
60
|
+
labels: ['billing', 'technical', 'refund'],
|
|
61
|
+
provider: 'typesafe',
|
|
62
|
+
model: 'jev-1.13.0',
|
|
63
|
+
threshold: 0.5,
|
|
64
|
+
signal: ctx.signal,
|
|
65
|
+
costContext: { projectId: input.projectId },
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`provider` is the registered map key; `model` is a model ID supported by that
|
|
70
|
+
endpoint. For Laya automatic language routing use `provider: 'laya', model: 'auto'`;
|
|
71
|
+
an explicit checkpoint must be configured on your Laya service.
|
|
72
|
+
|
|
73
|
+
| Setting | Resolution |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| Omitted `provider` | Existing default text provider, even when `decisions.defaultProvider` is set |
|
|
76
|
+
| Decision `model` | Per-call `model` → `decisions.defaultModel` → adapter default |
|
|
77
|
+
| Text `model` | Per-call `model` → AI service `defaultModel` → adapter default |
|
|
78
|
+
| Decision `threshold` | Inclusive probability cutoff in [0, 1], default 0.5 |
|
|
79
|
+
|
|
80
|
+
For a generative provider, pass its registered name and model and omit `threshold`:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const labels = await ctx.ai.classify({
|
|
84
|
+
text: input.ticketText,
|
|
85
|
+
labels: ['billing', 'technical'],
|
|
86
|
+
provider: 'openai',
|
|
87
|
+
model: 'gpt-6-sol',
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Native classification accepts 1–256 nonempty labels, batches one independent
|
|
92
|
+
probability question per label, and returns matching labels in input order. Zero
|
|
93
|
+
or multiple matches are valid. `threshold` is rejected for text providers. Use
|
|
94
|
+
`decide()` with a choice question when exactly one choice and its distribution
|
|
95
|
+
are required; generative models are not a `decide()` backend.
|
|
96
|
+
|
|
97
|
+
## Cost recording and tests
|
|
98
|
+
|
|
99
|
+
Persist the existing `onAICostRecorded` hook. Native classification records one
|
|
100
|
+
`operation: 'classify'` row per dispatched logical call, including failures, with
|
|
101
|
+
actual model, usage, cost, tenant/actor, and `costContext`. It does not create an
|
|
102
|
+
extra `decide` row. Unknown cost remains `null`; never invent zero to bypass a
|
|
103
|
+
budget. TypeSafe uses adapter pricing; Laya uses optional `costPerRequestUsd`.
|
|
104
|
+
|
|
105
|
+
Use `mockAI({ classify: ['billing'] })` through `createTestContext` and
|
|
106
|
+
`runCapability` / `simulateFlow` for application tests. Read the installed provider's
|
|
107
|
+
`instructions/README.md` for adapter tests. Live Laya inference is opt-in; keep it
|
|
108
|
+
out of routine tests.
|
|
109
|
+
|
|
110
|
+
After upgrading core, run `plumbus init --patch --agent all` and `plumbus doctor`
|
|
111
|
+
to refresh agent wiring to **v17**, preserving app-owned text outside managed blocks.
|
|
112
|
+
|
|
113
|
+
See [AI operations](ai.md), [instruction index](README.md), and the
|
|
114
|
+
[decision provider guide](https://github.com/plumbus-framework/plumbus/blob/main/docs/ai/decision-providers.md).
|
package/instructions/ai.md
CHANGED
|
@@ -70,6 +70,11 @@ const invoice = await ctx.ai.extract({
|
|
|
70
70
|
|
|
71
71
|
### Classify
|
|
72
72
|
|
|
73
|
+
**Start with [the classification recipe](ai-classification.md)** for provider/model
|
|
74
|
+
selection, TypeSafe/Jev and Laya registration, defaults, thresholds, and cost hooks
|
|
75
|
+
(core **0.7.4+** / **0.8.0-beta.6+**). Use `classify()` for matching labels and `decide()` for richer
|
|
76
|
+
typed questions. Keep calls inside capabilities/flows.
|
|
77
|
+
|
|
73
78
|
Classify text into provided categories:
|
|
74
79
|
|
|
75
80
|
```ts
|
|
@@ -115,7 +120,7 @@ await ctx.ai.generateWithUsage({
|
|
|
115
120
|
});
|
|
116
121
|
```
|
|
117
122
|
|
|
118
|
-
Omit `reasoning` to inherit prompt/config; use `null` to restore the provider/model default for one call, clearing both inherited `reasoning` and inherited legacy `reasoningEffort`. Explicit modes are `{ mode:'disabled' }`, `{ mode:'effort', effort:'minimal'|'low'|'medium'|'high'|'xhigh'|'max' }`, and `{ mode:'budget', maxTokens }`. Built-in core adapters translate the intent: OpenAI uses Chat Completions normally and switches caller-tool requests that need active/default GPT-5.6 reasoning to the Responses API; Anthropic uses `thinking` + `output_config.effort`. Responses tool continuations are stateless (`store:false`) and preserve encrypted reasoning items through server-owned `providerState`. Custom providers translate the contract in their own `AIProviderAdapter`. Unsupported modes fail with `AIInvalidRequestError` before provider I/O when the adapter can identify the incompatibility. Deprecated `reasoningEffort` remains the unchanged OpenAI-only `'low' | 'medium' | 'high'` shorthand.
|
|
123
|
+
Omit `reasoning` to inherit prompt/config; use `null` to restore the provider/model default for one call, clearing both inherited `reasoning` and inherited legacy `reasoningEffort`. Explicit modes are `{ mode:'disabled' }`, `{ mode:'effort', effort:'minimal'|'low'|'medium'|'high'|'xhigh'|'max' }`, and `{ mode:'budget', maxTokens }`. Built-in core adapters translate the intent: OpenAI uses Chat Completions normally and switches caller-tool requests that need active/default GPT-5.6 or GPT-6 reasoning to the Responses API; Anthropic uses `thinking` + `output_config.effort`. GPT-6 Chat Completions use `max_completion_tokens`; GPT-6 requests omit sampling temperature unless reasoning is explicitly disabled. Responses tool continuations are stateless (`store:false`) and preserve encrypted reasoning items through server-owned `providerState`. Custom providers translate the contract in their own `AIProviderAdapter`. Unsupported modes fail with `AIInvalidRequestError` before provider I/O when the adapter can identify the incompatibility. Deprecated `reasoningEffort` remains the unchanged OpenAI-only `'low' | 'medium' | 'high'` shorthand.
|
|
119
124
|
|
|
120
125
|
### Tool calling (provider-native)
|
|
121
126
|
|
|
@@ -382,3 +387,25 @@ See `docs/ai/ai-integration.md` and `docs/upgrading-contract-alignment.md` §12.
|
|
|
382
387
|
- With security configured, generate/stream/extract/classify apply the field-classification policy. Extract/classify use the `text` field; arbitrary free-text PII is not automatically detected. Explainability stores redacted input.
|
|
383
388
|
- Unknown prior spend rejects further requests when a dollar cap is configured. Local/unpriced providers still work without dollar caps; explicit free prices stay supported. Never supply fake zero costs to bypass budgets.
|
|
384
389
|
- Read [the security release checklist](./upgrading-security-release.md) before upgrading custom cost hooks or AI wrappers.
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
## Typed decisions (core 0.7.4+ / 0.8.0-beta.6+)
|
|
393
|
+
|
|
394
|
+
For choices, scores, and probabilities, use `ctx.ai.decide()` inside capabilities
|
|
395
|
+
and flows. Define reusable contracts with `defineDecision` from
|
|
396
|
+
`@plumbus/ai-decision`; CLI startup discovers `app/decisions/`. The shared contract
|
|
397
|
+
package is provided by core; install only the TypeSafe/Laya provider required by
|
|
398
|
+
the app. Export `decisions = { providers, defaultProvider }` from `app/server.ts`
|
|
399
|
+
for both API and workers, using `createTypeSafeDecisionAdapter` or
|
|
400
|
+
`createLayaDecisionAdapter` at that server-owned boundary. Do not register these
|
|
401
|
+
adapters as text-completion providers or call them directly for app business logic.
|
|
402
|
+
|
|
403
|
+
Core records `operation: 'decide'` with actual model, usage, cost, tenant/actor,
|
|
404
|
+
optional `decisionName`, and the caller's `costContext`. Existing
|
|
405
|
+
`onAICostRecorded(record, costContext, db)` hooks persist these rows; include the
|
|
406
|
+
new operation in any app-owned ledger enum/schema. Failed responses and cancelled
|
|
407
|
+
calls also produce rows. Unknown USD cost is null, never a free zero. Security
|
|
408
|
+
scans state and structured questions; budgets are checked before provider work.
|
|
409
|
+
Use `mockAI({ decide: result })` and test through `runCapability`/`simulateFlow`.
|
|
410
|
+
|
|
411
|
+
Guide: https://github.com/plumbus-framework/plumbus/blob/main/docs/ai/decision-providers.md
|
|
@@ -43,4 +43,4 @@ Run lint, format checking, typechecking, tests, and packed npm install checks be
|
|
|
43
43
|
|
|
44
44
|
## Consumer upgrade
|
|
45
45
|
|
|
46
|
-
Read [upgrading-security-release.md](./upgrading-security-release.md) and the 0.8 notes in the root docs, explicitly select the new package versions for every installed Plumbus add-on, and run `plumbus init --patch` for agent wiring **
|
|
46
|
+
Read [upgrading-security-release.md](./upgrading-security-release.md) and the 0.8 notes in the root docs, explicitly select the new package versions for every installed Plumbus add-on, and run `plumbus init --patch --agent all` for current agent wiring (**v17** with core 0.7.4+ / 0.8.0-beta.6+). For classification/provider/model selection, read [ai-classification.md](./ai-classification.md). Keep application business logic in Plumbus primitives and `ctx.*`; do not bypass security checks to make a migration pass.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumbus/core",
|
|
3
|
-
"version": "0.8.0-beta.
|
|
3
|
+
"version": "0.8.0-beta.7",
|
|
4
4
|
"description": "Plumbus framework core — types, SDK, runtime, CLI, test utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -89,7 +89,8 @@
|
|
|
89
89
|
"xml-crypto": "^6.1.2",
|
|
90
90
|
"xpath": "^0.0.34",
|
|
91
91
|
"zod": "^3.24.0",
|
|
92
|
-
"zod-to-json-schema": "^3.25.2"
|
|
92
|
+
"zod-to-json-schema": "^3.25.2",
|
|
93
|
+
"@plumbus/ai-decision": "~0.3.0-beta.0"
|
|
93
94
|
},
|
|
94
95
|
"peerDependencies": {
|
|
95
96
|
"@plumbus/api": ">=0.3.0-beta.0 <0.4.0",
|
|
@@ -121,10 +122,10 @@
|
|
|
121
122
|
"@vitest/browser": "^3.0.0",
|
|
122
123
|
"esbuild": "^0.25.12",
|
|
123
124
|
"typescript": "^5.7.0",
|
|
124
|
-
"@plumbus/api": "0.3.0-beta.0",
|
|
125
125
|
"@plumbus/ai-bedrock": "0.3.0-beta.0",
|
|
126
|
-
"@plumbus/
|
|
127
|
-
"@plumbus/mcp": "0.7.0-beta.0"
|
|
126
|
+
"@plumbus/api": "0.3.0-beta.0",
|
|
127
|
+
"@plumbus/mcp": "0.7.0-beta.0",
|
|
128
|
+
"@plumbus/voice": "0.6.0-beta.1"
|
|
128
129
|
},
|
|
129
130
|
"scripts": {
|
|
130
131
|
"build": "tsc -b",
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type AIService, type RAGPipelineConfig, type RunToolLoopParams } from '@plumbus/core';
|
|
2
|
-
export declare function legacyConsumer(ai: AIService, params: RunToolLoopParams): Promise<number>;
|
|
3
|
-
export declare const legacyEmbeddingCallback: RAGPipelineConfig['onEmbeddingCost'];
|
|
4
|
-
export declare const uncheckedEstimate: number;
|
|
5
|
-
//# sourceMappingURL=legacy-cost-api.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"legacy-cost-api.d.ts","sourceRoot":"","sources":["../../../src/ai/__typecheck-fixtures__/legacy-cost-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AAEvB,wBAAsB,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9F;AAED,eAAO,MAAM,uBAAuB,EAAE,iBAAiB,CAAC,iBAAiB,CAGxE,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,MAAyC,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { calculateModelCost, estimateModelCost, runToolLoop, } from '@plumbus/core';
|
|
2
|
-
export async function legacyConsumer(ai, params) {
|
|
3
|
-
const result = await ai.generateWithUsage({ prompt: 'p', input: {} });
|
|
4
|
-
const cost = result.cost;
|
|
5
|
-
const loop = await runToolLoop(ai, params);
|
|
6
|
-
const total = loop.aggregatedCost;
|
|
7
|
-
return cost + total + calculateModelCost(1, 1, 'local');
|
|
8
|
-
}
|
|
9
|
-
export const legacyEmbeddingCallback = (info) => {
|
|
10
|
-
const numericCost = info.cost;
|
|
11
|
-
void numericCost;
|
|
12
|
-
};
|
|
13
|
-
// @ts-expect-error Unknown-aware estimates cannot be treated as definitely priced.
|
|
14
|
-
export const uncheckedEstimate = estimateModelCost(1, 1, 'local');
|
|
15
|
-
//# sourceMappingURL=legacy-cost-api.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"legacy-cost-api.js","sourceRoot":"","sources":["../../../src/ai/__typecheck-fixtures__/legacy-cost-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,GAIZ,MAAM,eAAe,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAa,EAAE,MAAyB;IAC3E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,IAAI,GAAW,MAAM,CAAC,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAW,IAAI,CAAC,cAAc,CAAC;IAC1C,OAAO,IAAI,GAAG,KAAK,GAAG,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAyC,CAAC,IAAI,EAAE,EAAE;IACpF,MAAM,WAAW,GAAW,IAAI,CAAC,IAAI,CAAC;IACtC,KAAK,WAAW,CAAC;AACnB,CAAC,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAW,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC"}
|