poke-crucible 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/battle/pairing.d.ts +25 -0
- package/dist/battle/pairing.js +59 -0
- package/dist/battle/pairing.js.map +1 -0
- package/dist/battle/pool.d.ts +25 -0
- package/dist/battle/pool.js +97 -0
- package/dist/battle/pool.js.map +1 -0
- package/dist/battle/run-battle.d.ts +13 -0
- package/dist/battle/run-battle.js +49 -0
- package/dist/battle/run-battle.js.map +1 -0
- package/dist/battle/worker.d.ts +1 -0
- package/dist/battle/worker.js +21 -0
- package/dist/battle/worker.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +326 -0
- package/dist/cli.js.map +1 -0
- package/dist/critic/agent-sdk-model.d.ts +27 -0
- package/dist/critic/agent-sdk-model.js +21 -0
- package/dist/critic/agent-sdk-model.js.map +1 -0
- package/dist/critic/critique.d.ts +21 -0
- package/dist/critic/critique.js +51 -0
- package/dist/critic/critique.js.map +1 -0
- package/dist/critic/evidence.d.ts +24 -0
- package/dist/critic/evidence.js +17 -0
- package/dist/critic/evidence.js.map +1 -0
- package/dist/critic/llm.d.ts +34 -0
- package/dist/critic/llm.js +23 -0
- package/dist/critic/llm.js.map +1 -0
- package/dist/critic/parse.d.ts +5 -0
- package/dist/critic/parse.js +84 -0
- package/dist/critic/parse.js.map +1 -0
- package/dist/critic/prompt.d.ts +14 -0
- package/dist/critic/prompt.js +56 -0
- package/dist/critic/prompt.js.map +1 -0
- package/dist/critic/types.d.ts +52 -0
- package/dist/critic/types.js +2 -0
- package/dist/critic/types.js.map +1 -0
- package/dist/designer/agent-sdk-model.d.ts +30 -0
- package/dist/designer/agent-sdk-model.js +62 -0
- package/dist/designer/agent-sdk-model.js.map +1 -0
- package/dist/designer/design.d.ts +12 -0
- package/dist/designer/design.js +218 -0
- package/dist/designer/design.js.map +1 -0
- package/dist/designer/fitness.d.ts +25 -0
- package/dist/designer/fitness.js +24 -0
- package/dist/designer/fitness.js.map +1 -0
- package/dist/designer/model.d.ts +14 -0
- package/dist/designer/model.js +27 -0
- package/dist/designer/model.js.map +1 -0
- package/dist/designer/mutate.d.ts +31 -0
- package/dist/designer/mutate.js +209 -0
- package/dist/designer/mutate.js.map +1 -0
- package/dist/designer/rng.d.ts +17 -0
- package/dist/designer/rng.js +40 -0
- package/dist/designer/rng.js.map +1 -0
- package/dist/designer/types.d.ts +103 -0
- package/dist/designer/types.js +2 -0
- package/dist/designer/types.js.map +1 -0
- package/dist/evaluate.d.ts +11 -0
- package/dist/evaluate.js +99 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/gauntlet/gauntlet.d.ts +18 -0
- package/dist/gauntlet/gauntlet.js +41 -0
- package/dist/gauntlet/gauntlet.js.map +1 -0
- package/dist/gauntlet/teams-g1.d.ts +23 -0
- package/dist/gauntlet/teams-g1.js +476 -0
- package/dist/gauntlet/teams-g1.js.map +1 -0
- package/dist/gauntlet/teams-g2.d.ts +14 -0
- package/dist/gauntlet/teams-g2.js +725 -0
- package/dist/gauntlet/teams-g2.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/agent-query.d.ts +21 -0
- package/dist/llm/agent-query.js +70 -0
- package/dist/llm/agent-query.js.map +1 -0
- package/dist/pilot/damage.d.ts +34 -0
- package/dist/pilot/damage.js +75 -0
- package/dist/pilot/damage.js.map +1 -0
- package/dist/pilot/eval-pilot.d.ts +39 -0
- package/dist/pilot/eval-pilot.js +161 -0
- package/dist/pilot/eval-pilot.js.map +1 -0
- package/dist/pilot/pilot.d.ts +71 -0
- package/dist/pilot/pilot.js +290 -0
- package/dist/pilot/pilot.js.map +1 -0
- package/dist/ranking.d.ts +25 -0
- package/dist/ranking.js +40 -0
- package/dist/ranking.js.map +1 -0
- package/dist/seed.d.ts +13 -0
- package/dist/seed.js +42 -0
- package/dist/seed.js.map +1 -0
- package/dist/team.d.ts +29 -0
- package/dist/team.js +100 -0
- package/dist/team.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse-and-validate the model's text into a {@link Critique}. The Agent SDK is
|
|
3
|
+
* prose-first (no strict output schema), so we extract the JSON object, coerce
|
|
4
|
+
* fields defensively, and — honouring the PRD's "suggestions are legality-checked"
|
|
5
|
+
* decision — keep a `revisedPaste` only if it is a legal Gen 3 OU Team.
|
|
6
|
+
*/
|
|
7
|
+
import { parseAndValidate } from '../team.js';
|
|
8
|
+
export class CritiqueParseError extends Error {
|
|
9
|
+
name = 'CritiqueParseError';
|
|
10
|
+
}
|
|
11
|
+
/** Pull the first balanced-looking JSON object out of the model's text. */
|
|
12
|
+
function extractJsonObject(text) {
|
|
13
|
+
const trimmed = text.trim();
|
|
14
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(trimmed);
|
|
15
|
+
const body = fenced?.[1] ?? trimmed;
|
|
16
|
+
const start = body.indexOf('{');
|
|
17
|
+
const end = body.lastIndexOf('}');
|
|
18
|
+
if (start < 0 || end <= start) {
|
|
19
|
+
throw new CritiqueParseError('no JSON object found in model output');
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(body.slice(start, end + 1));
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
throw new CritiqueParseError(`invalid JSON: ${e.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function asString(v) {
|
|
29
|
+
return typeof v === 'string' ? v : '';
|
|
30
|
+
}
|
|
31
|
+
function asStringArray(v) {
|
|
32
|
+
return Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
|
|
33
|
+
}
|
|
34
|
+
function asSeverity(v) {
|
|
35
|
+
return v === 'high' || v === 'medium' || v === 'low' ? v : 'medium';
|
|
36
|
+
}
|
|
37
|
+
function coerceWeakness(w) {
|
|
38
|
+
const o = (w ?? {});
|
|
39
|
+
return {
|
|
40
|
+
summary: asString(o['summary']),
|
|
41
|
+
exploitedBy: asStringArray(o['exploitedBy']),
|
|
42
|
+
mechanism: asString(o['mechanism']),
|
|
43
|
+
severity: asSeverity(o['severity']),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function coerceFix(f) {
|
|
47
|
+
const o = (f ?? {});
|
|
48
|
+
return { change: asString(o['change']), rationale: asString(o['rationale']) };
|
|
49
|
+
}
|
|
50
|
+
export function parseCritique(text, input, model) {
|
|
51
|
+
const raw = extractJsonObject(text);
|
|
52
|
+
if (!raw || typeof raw !== 'object') {
|
|
53
|
+
throw new CritiqueParseError('model output was not a JSON object');
|
|
54
|
+
}
|
|
55
|
+
const o = raw;
|
|
56
|
+
const overall = asString(o['overall']);
|
|
57
|
+
const weaknesses = Array.isArray(o['weaknesses']) ? o['weaknesses'].map(coerceWeakness) : [];
|
|
58
|
+
const fixes = Array.isArray(o['fixes']) ? o['fixes'].map(coerceFix) : [];
|
|
59
|
+
const caveats = asStringArray(o['caveats']);
|
|
60
|
+
if (!overall && weaknesses.length === 0) {
|
|
61
|
+
throw new CritiqueParseError('critique had neither an overall summary nor any weaknesses');
|
|
62
|
+
}
|
|
63
|
+
const critique = {
|
|
64
|
+
team: input.row.team,
|
|
65
|
+
strength: input.row.strength,
|
|
66
|
+
overall,
|
|
67
|
+
weaknesses,
|
|
68
|
+
fixes,
|
|
69
|
+
caveats,
|
|
70
|
+
model,
|
|
71
|
+
seed: input.seed,
|
|
72
|
+
};
|
|
73
|
+
if (input.gauntletVersion)
|
|
74
|
+
critique.gauntletVersion = input.gauntletVersion;
|
|
75
|
+
// Keep a proposed revised Team only if it is actually legal Gen 3 OU.
|
|
76
|
+
const revised = o['revisedPaste'];
|
|
77
|
+
if (typeof revised === 'string' && revised.trim()) {
|
|
78
|
+
const { legal } = parseAndValidate([{ name: input.row.team, paste: revised }]);
|
|
79
|
+
if (legal.length === 1)
|
|
80
|
+
critique.revisedPaste = revised.trim();
|
|
81
|
+
}
|
|
82
|
+
return critique;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/critic/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt assembly — builds the system + user messages the Critic model sees
|
|
3
|
+
* from a {@link CritiqueContext}. The ADR-0004 guardrail is baked into the
|
|
4
|
+
* system prompt so the model caveats verdicts that lean on the Pilot's known
|
|
5
|
+
* offense bias.
|
|
6
|
+
*/
|
|
7
|
+
import type { CritiqueContext } from './evidence.js';
|
|
8
|
+
export interface CritiquePrompt {
|
|
9
|
+
system: string;
|
|
10
|
+
user: string;
|
|
11
|
+
}
|
|
12
|
+
/** The ADR-0004 caveat, stated for the model. */
|
|
13
|
+
export declare const PILOT_CAVEAT: string;
|
|
14
|
+
export declare function buildPrompt(ctx: CritiqueContext): CritiquePrompt;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** The ADR-0004 caveat, stated for the model. */
|
|
2
|
+
export const PILOT_CAVEAT = 'The win-rates come from a fixed, competent-but-greedy heuristic Pilot that ' +
|
|
3
|
+
'drives BOTH sides, so skill is held constant. This Pilot somewhat UNDER-RATES ' +
|
|
4
|
+
'stall and defensive play: it does not fully value long-term Toxic / hazard / ' +
|
|
5
|
+
'recovery attrition. Treat a poor result against offense as real, but be ' +
|
|
6
|
+
'cautious about over-reading a poor result that hinges on the Pilot mis-piloting ' +
|
|
7
|
+
'a defensive plan — and say so in `caveats` when a verdict depends on it.';
|
|
8
|
+
const JSON_SHAPE = '{"overall": string, "weaknesses": [{"summary": string, "exploitedBy": string[], ' +
|
|
9
|
+
'"mechanism": string, "severity": "high"|"medium"|"low"}], "fixes": [{"change": ' +
|
|
10
|
+
'string, "rationale": string}], "caveats": string[], "revisedPaste": string | null}';
|
|
11
|
+
function pct(x) {
|
|
12
|
+
return `${Math.round(x * 100)}%`;
|
|
13
|
+
}
|
|
14
|
+
function summarize(matchups) {
|
|
15
|
+
return matchups
|
|
16
|
+
.map((m) => `${m.opponent}${m.archetype ? ` [${m.archetype}]` : ''} ${pct(m.winRate)}`)
|
|
17
|
+
.join(', ');
|
|
18
|
+
}
|
|
19
|
+
export function buildPrompt(ctx) {
|
|
20
|
+
// The full table is small for the current Gauntlet; the worst/best highlights
|
|
21
|
+
// focus the model (and are the compact evidence to lead with as it grows).
|
|
22
|
+
const table = [...ctx.all]
|
|
23
|
+
.sort((a, b) => a.winRate - b.winRate)
|
|
24
|
+
.map((m) => `- ${pct(m.winRate)} vs ${m.opponent}${m.archetype ? ` [${m.archetype}]` : ''} ` +
|
|
25
|
+
`(${m.battles} battles)`)
|
|
26
|
+
.join('\n');
|
|
27
|
+
const system = [
|
|
28
|
+
'You are the Critic: a rigorous Gen 3 OU team critic.',
|
|
29
|
+
'You scrutinise ONE team using its battle results and explain, specifically and ' +
|
|
30
|
+
'mechanically, its weaknesses and matchup holes, then suggest concrete, legal ' +
|
|
31
|
+
'Gen 3 OU fixes. Ground every claim in the provided results and team list — ' +
|
|
32
|
+
'no generic Pokémon platitudes. Tie each weakness to the Archetype(s) that ' +
|
|
33
|
+
'exploit it.',
|
|
34
|
+
PILOT_CAVEAT,
|
|
35
|
+
`Respond with ONLY a JSON object (no prose, no code fences) of this exact shape:\n${JSON_SHAPE}`,
|
|
36
|
+
'`exploitedBy` MUST use the bracketed Archetype label(s) from the matchup table ' +
|
|
37
|
+
'(e.g. "Special Offense"), never the opponent team name. `revisedPaste` is ' +
|
|
38
|
+
'optional: a full LEGAL Showdown paste of the team with your fixes applied, or null.',
|
|
39
|
+
].join('\n\n');
|
|
40
|
+
const user = [
|
|
41
|
+
`Team: ${ctx.team}`,
|
|
42
|
+
`Overall Strength vs the Gauntlet (${ctx.gauntletVersion ?? 'n/a'}): ${pct(ctx.strength)} ` +
|
|
43
|
+
`over ${ctx.battles} battles (seed ${ctx.seed}).`,
|
|
44
|
+
'',
|
|
45
|
+
'Team (Showdown paste):',
|
|
46
|
+
ctx.paste,
|
|
47
|
+
'',
|
|
48
|
+
`Weakest matchups (focus here): ${summarize(ctx.worst)}`,
|
|
49
|
+
`Best matchups: ${summarize(ctx.best)}`,
|
|
50
|
+
'',
|
|
51
|
+
'Per-matchup win-rates (worst first):',
|
|
52
|
+
table,
|
|
53
|
+
].join('\n');
|
|
54
|
+
return { system, user };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/critic/prompt.ts"],"names":[],"mappings":"AAaA,iDAAiD;AACjD,MAAM,CAAC,MAAM,YAAY,GACvB,6EAA6E;IAC7E,gFAAgF;IAChF,+EAA+E;IAC/E,0EAA0E;IAC1E,kFAAkF;IAClF,0EAA0E,CAAC;AAE7E,MAAM,UAAU,GACd,kFAAkF;IAClF,iFAAiF;IACjF,oFAAoF,CAAC;AAEvF,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;AACnC,CAAC;AAED,SAAS,SAAS,CAAC,QAAkC;IACnD,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;SACtF,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAoB;IAC9C,8EAA8E;IAC9E,2EAA2E;IAC3E,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;SACvB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;SACrC,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG;QAChF,IAAI,CAAC,CAAC,OAAO,WAAW,CAC3B;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,MAAM,GAAG;QACb,sDAAsD;QACtD,iFAAiF;YAC/E,+EAA+E;YAC/E,6EAA6E;YAC7E,4EAA4E;YAC5E,aAAa;QACf,YAAY;QACZ,oFAAoF,UAAU,EAAE;QAChG,iFAAiF;YAC/E,4EAA4E;YAC5E,qFAAqF;KACxF,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEf,MAAM,IAAI,GAAG;QACX,SAAS,GAAG,CAAC,IAAI,EAAE;QACnB,qCAAqC,GAAG,CAAC,eAAe,IAAI,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG;YACzF,QAAQ,GAAG,CAAC,OAAO,kBAAkB,GAAG,CAAC,IAAI,IAAI;QACnD,EAAE;QACF,wBAAwB;QACxB,GAAG,CAAC,KAAK;QACT,EAAE;QACF,kCAAkC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACxD,kBAAkB,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QACvC,EAAE;QACF,sCAAsC;QACtC,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Critique contract — the structured result the Critic (Slice 2) produces
|
|
3
|
+
* from one Team's Slice-1 evaluation. This is what the CLI prints and what the
|
|
4
|
+
* Slice-3 Designer will reuse to name and explain what it discovers.
|
|
5
|
+
*/
|
|
6
|
+
import type { StrengthRow } from '../types.js';
|
|
7
|
+
export type Severity = 'high' | 'medium' | 'low';
|
|
8
|
+
/** One matchup hole or structural weakness, tied to what exploits it. */
|
|
9
|
+
export interface CritiqueWeakness {
|
|
10
|
+
/** One-line statement of the weakness. */
|
|
11
|
+
summary: string;
|
|
12
|
+
/** Archetype label(s) that exploit it (matching the Gauntlet's labels). */
|
|
13
|
+
exploitedBy: string[];
|
|
14
|
+
/** Why it happens — the threat plus what the Team lacks. */
|
|
15
|
+
mechanism: string;
|
|
16
|
+
severity: Severity;
|
|
17
|
+
}
|
|
18
|
+
/** A concrete, actionable change to shore up a weakness. */
|
|
19
|
+
export interface CritiqueFix {
|
|
20
|
+
change: string;
|
|
21
|
+
rationale: string;
|
|
22
|
+
}
|
|
23
|
+
/** The full critique of one Team. */
|
|
24
|
+
export interface Critique {
|
|
25
|
+
team: string;
|
|
26
|
+
/** Overall Strength echoed from the evaluation, in [0, 1]. */
|
|
27
|
+
strength: number;
|
|
28
|
+
/** Plain-language summary of the Team's biggest problems. */
|
|
29
|
+
overall: string;
|
|
30
|
+
/** Ranked weaknesses, most severe first. */
|
|
31
|
+
weaknesses: CritiqueWeakness[];
|
|
32
|
+
fixes: CritiqueFix[];
|
|
33
|
+
/** Caveats the Critic flagged — notably where a verdict leans on the Pilot's
|
|
34
|
+
* known offense bias (ADR 0004). */
|
|
35
|
+
caveats: string[];
|
|
36
|
+
/** Optional full legal Showdown paste with the fixes applied. */
|
|
37
|
+
revisedPaste?: string;
|
|
38
|
+
/** Which model produced the critique (for reproducibility). */
|
|
39
|
+
model: string;
|
|
40
|
+
/** Gauntlet version and seed of the underlying evaluation. */
|
|
41
|
+
gauntletVersion?: string;
|
|
42
|
+
seed: string;
|
|
43
|
+
}
|
|
44
|
+
/** Input to {@link critique}: one Team's paste plus its Slice-1 result. */
|
|
45
|
+
export interface CritiqueInput {
|
|
46
|
+
/** Standard Showdown paste — lets the Critic reason about mechanism and fixes. */
|
|
47
|
+
paste: string;
|
|
48
|
+
/** That Team's row from an `evaluate()` result. */
|
|
49
|
+
row: StrengthRow;
|
|
50
|
+
seed: string;
|
|
51
|
+
gauntletVersion?: string;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/critic/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live {@link DesignerModel}, backed by the Claude Agent SDK on the
|
|
3
|
+
* maintainer's subscription (like the Critic — Slice 2). `proposeMutations` asks
|
|
4
|
+
* for improved legal Team pastes (the search legality-checks them before use);
|
|
5
|
+
* `nameArchetype` labels a Team. Robust to malformed output: returns nothing
|
|
6
|
+
* rather than throwing, so a bad reply just costs a generation's LLM injection.
|
|
7
|
+
*/
|
|
8
|
+
import type { DesignerModel } from './types.js';
|
|
9
|
+
import { type Effort } from '../llm/agent-query.js';
|
|
10
|
+
export declare const DEFAULT_DESIGNER_MODEL = "claude-sonnet-5";
|
|
11
|
+
export interface AgentSdkDesignerOptions {
|
|
12
|
+
model?: string;
|
|
13
|
+
effort?: Effort;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
/** How many variant pastes to ask for per call. */
|
|
16
|
+
proposals?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class AgentSdkDesignerModel implements DesignerModel {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
private readonly effort;
|
|
21
|
+
private readonly timeoutMs;
|
|
22
|
+
private readonly proposals;
|
|
23
|
+
constructor(options?: AgentSdkDesignerOptions);
|
|
24
|
+
proposeMutations(paste: string, critique?: string): Promise<string[]>;
|
|
25
|
+
nameArchetype(paste: string, note: string): Promise<{
|
|
26
|
+
archetype: string;
|
|
27
|
+
novel: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
private opts;
|
|
30
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { runAgentQuery } from '../llm/agent-query.js';
|
|
2
|
+
export const DEFAULT_DESIGNER_MODEL = 'claude-sonnet-5';
|
|
3
|
+
function extractJson(text) {
|
|
4
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(text.trim());
|
|
5
|
+
const body = fenced?.[1] ?? text.trim();
|
|
6
|
+
const start = Math.min(...['{', '['].map((c) => (body.indexOf(c) < 0 ? Infinity : body.indexOf(c))));
|
|
7
|
+
const end = Math.max(body.lastIndexOf('}'), body.lastIndexOf(']'));
|
|
8
|
+
if (!Number.isFinite(start) || end <= start)
|
|
9
|
+
return null;
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(body.slice(start, end + 1));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class AgentSdkDesignerModel {
|
|
18
|
+
name;
|
|
19
|
+
effort;
|
|
20
|
+
timeoutMs;
|
|
21
|
+
proposals;
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.name = options.model ?? DEFAULT_DESIGNER_MODEL;
|
|
24
|
+
this.effort = options.effort ?? 'low';
|
|
25
|
+
this.timeoutMs = options.timeoutMs ?? 120_000;
|
|
26
|
+
this.proposals = options.proposals ?? 2;
|
|
27
|
+
}
|
|
28
|
+
async proposeMutations(paste, critique) {
|
|
29
|
+
const system = 'You are a Gen 3 OU team designer. Given a team (and optionally a critique of it), ' +
|
|
30
|
+
`propose up to ${this.proposals} improved, fully LEGAL Gen 3 OU variants that address its ` +
|
|
31
|
+
'weaknesses — change members, sets, moves, items, or EVs as needed. Output ONLY a JSON ' +
|
|
32
|
+
'array of strings, where each string is a complete Showdown paste of one team. No prose.';
|
|
33
|
+
const user = `Team:\n${paste}${critique ? `\n\nCritique:\n${critique}` : ''}`;
|
|
34
|
+
try {
|
|
35
|
+
const parsed = extractJson(await runAgentQuery(system, user, this.opts()));
|
|
36
|
+
if (!Array.isArray(parsed))
|
|
37
|
+
return [];
|
|
38
|
+
return parsed.filter((p) => typeof p === 'string' && p.trim().length > 0);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async nameArchetype(paste, note) {
|
|
45
|
+
const system = 'Name the Gen 3 OU archetype of this team in 2-4 words (e.g. "Spikes stall", "Sand ' +
|
|
46
|
+
'offense", "Calm Mind balance"). Output ONLY JSON {"archetype": string, "novel": boolean}. ' +
|
|
47
|
+
'Set novel to true only if the strategy is unusual or creative for the metagame.';
|
|
48
|
+
const user = `Team:\n${paste}${note ? `\n\nNote: ${note}` : ''}`;
|
|
49
|
+
try {
|
|
50
|
+
const parsed = extractJson(await runAgentQuery(system, user, this.opts()));
|
|
51
|
+
const archetype = typeof parsed?.archetype === 'string' ? parsed.archetype : 'Unnamed';
|
|
52
|
+
return { archetype, novel: parsed?.novel === true };
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return { archetype: 'Unnamed', novel: false };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
opts() {
|
|
59
|
+
return { model: this.name, effort: this.effort, timeoutMs: this.timeoutMs };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=agent-sdk-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-sdk-model.js","sourceRoot":"","sources":["../../src/designer/agent-sdk-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CritiqueModel } from '../critic/llm.js';
|
|
2
|
+
import { type EvaluateRuntimeOptions } from '../evaluate.js';
|
|
3
|
+
import type { DesignInput, DesignResult, DesignerModel } from './types.js';
|
|
4
|
+
/** Identity of the Pilot the fitness is measured under (ADR 0002/0004). */
|
|
5
|
+
export declare const PILOT_ID = "greedy-heuristic-v1";
|
|
6
|
+
export interface DesignOptions {
|
|
7
|
+
runtime?: EvaluateRuntimeOptions;
|
|
8
|
+
/** When provided, the Critic critiques each generation's best Team and its
|
|
9
|
+
* critique drives the LLM's mutation proposals (User Story 11). */
|
|
10
|
+
critic?: CritiqueModel;
|
|
11
|
+
}
|
|
12
|
+
export declare function design(input: DesignInput, model: DesignerModel, options?: DesignOptions): Promise<DesignResult>;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Designer seam. `design` runs the discovery loop: initialise a population
|
|
3
|
+
* (seed Teams + a gene pool drawn from the Gauntlet), then each generation score
|
|
4
|
+
* every Team's composite fitness (Gauntlet Strength via `evaluate`, cached, with
|
|
5
|
+
* an adaptive screen; plus a peer round-robin), select the fittest, breed the
|
|
6
|
+
* next generation by mutation and crossover (with LLM-proposed variants, driven
|
|
7
|
+
* by the Slice-2 Critic), and carry the elite forward. Deterministic under the
|
|
8
|
+
* seed; reuses the Slice-1 `evaluate` seam for all fitness — no direct sim access.
|
|
9
|
+
*/
|
|
10
|
+
import { critique } from '../critic/critique.js';
|
|
11
|
+
import { evaluate } from '../evaluate.js';
|
|
12
|
+
import { DEFAULT_GAUNTLET_VERSION, gauntletTeamData } from '../gauntlet/gauntlet.js';
|
|
13
|
+
import { parseAndValidate, toSubmissions } from '../team.js';
|
|
14
|
+
import { DEFAULT_WEIGHTS, composite, fitnessParts } from './fitness.js';
|
|
15
|
+
import { buildGenePool, buildMovePool, crossover, isLegal, mutate, parse, serialize, uniqueSpeciesTeam, } from './mutate.js';
|
|
16
|
+
import { Rng } from './rng.js';
|
|
17
|
+
/** Identity of the Pilot the fitness is measured under (ADR 0002/0004). */
|
|
18
|
+
export const PILOT_ID = 'greedy-heuristic-v1';
|
|
19
|
+
const BASE_BUDGET = {
|
|
20
|
+
population: 8,
|
|
21
|
+
generations: 4,
|
|
22
|
+
battlesPerPairing: 16,
|
|
23
|
+
elitism: 2,
|
|
24
|
+
battleBudget: 20_000,
|
|
25
|
+
weights: DEFAULT_WEIGHTS,
|
|
26
|
+
};
|
|
27
|
+
function resolveBudget(input) {
|
|
28
|
+
const battlesPerPairing = input?.battlesPerPairing ?? BASE_BUDGET.battlesPerPairing;
|
|
29
|
+
return {
|
|
30
|
+
population: input?.population ?? BASE_BUDGET.population,
|
|
31
|
+
generations: input?.generations ?? BASE_BUDGET.generations,
|
|
32
|
+
battlesPerPairing,
|
|
33
|
+
// Adaptive screen defaults to half the full budget (clamped to ≤ full).
|
|
34
|
+
screenBattlesPerPairing: Math.min(battlesPerPairing, input?.screenBattlesPerPairing ?? Math.max(1, Math.floor(battlesPerPairing / 2))),
|
|
35
|
+
battleBudget: input?.battleBudget ?? BASE_BUDGET.battleBudget,
|
|
36
|
+
elitism: input?.elitism ?? BASE_BUDGET.elitism,
|
|
37
|
+
weights: input?.weights ?? BASE_BUDGET.weights,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function tournament(scored, rng, k = 3) {
|
|
41
|
+
let best = scored[rng.int(scored.length)];
|
|
42
|
+
for (let i = 1; i < k; i++) {
|
|
43
|
+
const c = scored[rng.int(scored.length)];
|
|
44
|
+
if (c.fitness > best.fitness)
|
|
45
|
+
best = c;
|
|
46
|
+
}
|
|
47
|
+
return best;
|
|
48
|
+
}
|
|
49
|
+
export async function design(input, model, options = {}) {
|
|
50
|
+
const seed = input.seed ?? 'poke-crucible';
|
|
51
|
+
const gauntletVersion = input.gauntletVersion ?? DEFAULT_GAUNTLET_VERSION;
|
|
52
|
+
const budget = resolveBudget(input.budget);
|
|
53
|
+
const rng = new Rng(seed);
|
|
54
|
+
const gauntletTeams = gauntletTeamData(gauntletVersion);
|
|
55
|
+
const gauntletPastes = gauntletTeams.map((t) => t.paste);
|
|
56
|
+
const genePool = buildGenePool(gauntletPastes);
|
|
57
|
+
const movePool = buildMovePool(gauntletPastes);
|
|
58
|
+
let battlesRun = 0;
|
|
59
|
+
const ctx = {
|
|
60
|
+
budget,
|
|
61
|
+
seed,
|
|
62
|
+
gauntletVersion,
|
|
63
|
+
gauntletSize: gauntletTeams.length,
|
|
64
|
+
runtime: options.runtime ?? {},
|
|
65
|
+
addBattles: (n) => {
|
|
66
|
+
battlesRun += n;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const { legal, errors } = parseAndValidate(toSubmissions(input.seedTeams ?? []));
|
|
70
|
+
let counter = 0;
|
|
71
|
+
const makeMember = (team, lineage) => {
|
|
72
|
+
const { paste, packed } = serialize(team);
|
|
73
|
+
return { id: `m${counter++}`, team, paste, packed, lineage };
|
|
74
|
+
};
|
|
75
|
+
// --- Initial population: seed Teams, then random Teams from the gene pool.
|
|
76
|
+
let population = legal.map((t) => makeMember(t.team, { origin: 'seed', generation: 0, parents: [] }));
|
|
77
|
+
let guard = 0;
|
|
78
|
+
while (population.length < budget.population && guard++ < budget.population * 40) {
|
|
79
|
+
const t = uniqueSpeciesTeam(genePool, 6, rng);
|
|
80
|
+
if (t.length === 6 && isLegal(t)) {
|
|
81
|
+
population.push(makeMember(t, { origin: 'random', generation: 0, parents: [] }));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
population = population.slice(0, budget.population);
|
|
85
|
+
const gauntletCache = new Map();
|
|
86
|
+
let ranked = [];
|
|
87
|
+
let generations = 0;
|
|
88
|
+
for (let gen = 0; gen < budget.generations; gen++) {
|
|
89
|
+
await scoreGauntlet(ctx, population, gauntletCache, gen);
|
|
90
|
+
const peer = await scorePeers(ctx, population, gen);
|
|
91
|
+
generations = gen + 1;
|
|
92
|
+
ranked = population
|
|
93
|
+
.map((member) => {
|
|
94
|
+
const row = gauntletCache.get(member.packed);
|
|
95
|
+
const parts = fitnessParts(row, peer.get(member.id) ?? 0);
|
|
96
|
+
return { member, row, parts, fitness: composite(parts, budget.weights) };
|
|
97
|
+
})
|
|
98
|
+
.sort((a, b) => b.fitness - a.fitness);
|
|
99
|
+
if (gen === budget.generations - 1 || battlesRun >= budget.battleBudget)
|
|
100
|
+
break;
|
|
101
|
+
population = await breed(ctx, ranked, gen, model, options.critic, genePool, movePool, rng, makeMember);
|
|
102
|
+
}
|
|
103
|
+
// --- Name the Archetypes of the final ranked Teams.
|
|
104
|
+
const discovered = [];
|
|
105
|
+
for (const s of ranked) {
|
|
106
|
+
const { archetype, novel } = await model.nameArchetype(s.member.paste, `Strength ${Math.round(s.row.strength * 100)}%`);
|
|
107
|
+
discovered.push({
|
|
108
|
+
id: s.member.id,
|
|
109
|
+
paste: s.member.paste,
|
|
110
|
+
strength: s.row.strength,
|
|
111
|
+
fitness: s.fitness,
|
|
112
|
+
fitnessParts: s.parts,
|
|
113
|
+
archetype,
|
|
114
|
+
novel,
|
|
115
|
+
lineage: s.member.lineage,
|
|
116
|
+
matchups: s.row.matchups,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return { discovered, generations, seed, gauntletVersion, pilot: PILOT_ID, budget, battlesRun, errors };
|
|
120
|
+
}
|
|
121
|
+
/** Build the next generation: elitism + Critic-driven LLM proposals + variation. */
|
|
122
|
+
async function breed(ctx, ranked, gen, model, critic, genePool, movePool, rng, makeMember) {
|
|
123
|
+
const { budget } = ctx;
|
|
124
|
+
const next = ranked.slice(0, budget.elitism).map((s) => s.member);
|
|
125
|
+
const best = ranked[0];
|
|
126
|
+
// Reuse the Slice-2 Critic to explain the best Team; feed that into the proposer.
|
|
127
|
+
let critiqueNote;
|
|
128
|
+
if (critic) {
|
|
129
|
+
const c = await critique({ paste: best.member.paste, row: best.row, seed: ctx.seed, gauntletVersion: ctx.gauntletVersion }, critic);
|
|
130
|
+
critiqueNote = [c.overall, ...c.weaknesses.map((w) => `- ${w.summary}`)].join('\n');
|
|
131
|
+
}
|
|
132
|
+
for (const paste of await model.proposeMutations(best.member.paste, critiqueNote)) {
|
|
133
|
+
if (next.length >= budget.population)
|
|
134
|
+
break;
|
|
135
|
+
const team = parse(paste);
|
|
136
|
+
if (team && isLegal(team)) {
|
|
137
|
+
next.push(makeMember(team, { origin: 'mutation', generation: gen + 1, parents: [best.member.id], operator: 'llm' }));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
let offspringGuard = 0;
|
|
141
|
+
while (next.length < budget.population && offspringGuard++ < budget.population * 30) {
|
|
142
|
+
const a = tournament(ranked, rng);
|
|
143
|
+
if (rng.chance(0.3)) {
|
|
144
|
+
const b = tournament(ranked, rng);
|
|
145
|
+
const child = crossover(a.member.team, b.member.team, rng);
|
|
146
|
+
if (child) {
|
|
147
|
+
next.push(makeMember(child, {
|
|
148
|
+
origin: 'crossover', generation: gen + 1, parents: [a.member.id, b.member.id], operator: 'crossover',
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const m = mutate(a.member.team, genePool, rng, movePool);
|
|
154
|
+
if (m) {
|
|
155
|
+
next.push(makeMember(m.team, {
|
|
156
|
+
origin: 'mutation', generation: gen + 1, parents: [a.member.id], operator: m.operator,
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return next.slice(0, budget.population);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Evaluate Gauntlet Strength for any Members not already cached (by packed Team),
|
|
165
|
+
* with an adaptive screen: score all new Teams cheaply first, then re-evaluate
|
|
166
|
+
* only the top half at the full battle count (more battles where they matter).
|
|
167
|
+
*/
|
|
168
|
+
async function scoreGauntlet(ctx, members, cache, gen) {
|
|
169
|
+
const uncached = members.filter((m) => !cache.has(m.packed));
|
|
170
|
+
if (uncached.length === 0)
|
|
171
|
+
return;
|
|
172
|
+
const { budget } = ctx;
|
|
173
|
+
const full = budget.battlesPerPairing;
|
|
174
|
+
const screen = budget.screenBattlesPerPairing;
|
|
175
|
+
const evalAt = async (group, battles, tag) => {
|
|
176
|
+
const result = await evaluate({
|
|
177
|
+
teams: group.map((m) => ({ name: m.id, paste: m.paste })),
|
|
178
|
+
opposition: { mode: 'gauntlet', gauntletVersion: ctx.gauntletVersion },
|
|
179
|
+
battlesPerPairing: battles,
|
|
180
|
+
seed: `${ctx.seed}:g${gen}:${tag}`,
|
|
181
|
+
}, ctx.runtime);
|
|
182
|
+
ctx.addBattles(group.length * ctx.gauntletSize * battles);
|
|
183
|
+
for (const row of result.ranking) {
|
|
184
|
+
const m = group.find((x) => x.id === row.team);
|
|
185
|
+
if (m)
|
|
186
|
+
cache.set(m.packed, row);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
if (screen >= full) {
|
|
190
|
+
await evalAt(uncached, full, 'gauntlet');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
await evalAt(uncached, screen, 'screen');
|
|
194
|
+
const contenders = [...uncached]
|
|
195
|
+
.sort((a, b) => (cache.get(b.packed).strength - cache.get(a.packed).strength))
|
|
196
|
+
.slice(0, Math.max(1, Math.ceil(uncached.length / 2)));
|
|
197
|
+
await evalAt(contenders, full, 'gauntlet');
|
|
198
|
+
}
|
|
199
|
+
/** Peer round-robin Strength within the current population. */
|
|
200
|
+
async function scorePeers(ctx, members, gen) {
|
|
201
|
+
const map = new Map();
|
|
202
|
+
if (members.length < 2) {
|
|
203
|
+
for (const m of members)
|
|
204
|
+
map.set(m.id, 0.5);
|
|
205
|
+
return map;
|
|
206
|
+
}
|
|
207
|
+
const result = await evaluate({
|
|
208
|
+
teams: members.map((m) => ({ name: m.id, paste: m.paste })),
|
|
209
|
+
opposition: { mode: 'round-robin' },
|
|
210
|
+
battlesPerPairing: ctx.budget.battlesPerPairing,
|
|
211
|
+
seed: `${ctx.seed}:g${gen}:peer`,
|
|
212
|
+
}, ctx.runtime);
|
|
213
|
+
ctx.addBattles((members.length * (members.length - 1) / 2) * ctx.budget.battlesPerPairing);
|
|
214
|
+
for (const row of result.ranking)
|
|
215
|
+
map.set(row.team, row.strength);
|
|
216
|
+
return map;
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=design.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/designer/design.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite fitness — the signal the search optimises. Deliberately NOT raw
|
|
3
|
+
* win-rate: blending Gauntlet Strength with peer performance and a worst-matchup
|
|
4
|
+
* robustness floor rewards well-rounded Teams (no catastrophic matchup) and
|
|
5
|
+
* dampens raw win-rate's pull toward glass-cannon offense.
|
|
6
|
+
*
|
|
7
|
+
* TUNING FINDING (ADR 0004): this does NOT fully recover stall's value. The
|
|
8
|
+
* Pilot genuinely scores a stall Team's worst matchups near 0%, so its
|
|
9
|
+
* robustness floor is 0 and the term can't lift it — the offense lean can't be
|
|
10
|
+
* corrected downstream, only in the Pilot. What the robustness floor *does* do
|
|
11
|
+
* is reward robust offense (e.g. Choice Band, no 0% hole) over glass cannons —
|
|
12
|
+
* a legitimate design pressure, just not the stall rescue ADR 0004 hoped for.
|
|
13
|
+
* Re-tuning the weights (0.15 vs 0.30 vs 0.40 robustness) does not move stall.
|
|
14
|
+
*/
|
|
15
|
+
import type { StrengthRow } from '../types.js';
|
|
16
|
+
import type { FitnessParts, FitnessWeights } from './types.js';
|
|
17
|
+
export declare const DEFAULT_WEIGHTS: FitnessWeights;
|
|
18
|
+
/**
|
|
19
|
+
* The worst-matchup floor: the lowest per-matchup win-rate. Rewards a flat,
|
|
20
|
+
* robust matchup profile over a Team the Pilot merely offense-favours (which
|
|
21
|
+
* spikes some matchups to ~100% and zeroes others).
|
|
22
|
+
*/
|
|
23
|
+
export declare function robustnessFloor(row: StrengthRow): number;
|
|
24
|
+
export declare function fitnessParts(gauntletRow: StrengthRow, peerStrength: number): FitnessParts;
|
|
25
|
+
export declare function composite(parts: FitnessParts, weights?: FitnessWeights): number;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const DEFAULT_WEIGHTS = { gauntlet: 0.5, peer: 0.35, robustness: 0.15 };
|
|
2
|
+
/**
|
|
3
|
+
* The worst-matchup floor: the lowest per-matchup win-rate. Rewards a flat,
|
|
4
|
+
* robust matchup profile over a Team the Pilot merely offense-favours (which
|
|
5
|
+
* spikes some matchups to ~100% and zeroes others).
|
|
6
|
+
*/
|
|
7
|
+
export function robustnessFloor(row) {
|
|
8
|
+
if (row.matchups.length === 0)
|
|
9
|
+
return row.strength;
|
|
10
|
+
return Math.min(...row.matchups.map((m) => m.winRate));
|
|
11
|
+
}
|
|
12
|
+
export function fitnessParts(gauntletRow, peerStrength) {
|
|
13
|
+
return {
|
|
14
|
+
gauntlet: gauntletRow.strength,
|
|
15
|
+
peer: peerStrength,
|
|
16
|
+
robustness: robustnessFloor(gauntletRow),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function composite(parts, weights = DEFAULT_WEIGHTS) {
|
|
20
|
+
return (weights.gauntlet * parts.gauntlet +
|
|
21
|
+
weights.peer * parts.peer +
|
|
22
|
+
weights.robustness * parts.robustness);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=fitness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fitness.js","sourceRoot":"","sources":["../../src/designer/fitness.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,eAAe,GAAmB,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAE/F;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAgB;IAC9C,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAC;IACnD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAwB,EAAE,YAAoB;IACzE,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,IAAI,EAAE,YAAY;QAClB,UAAU,EAAE,eAAe,CAAC,WAAW,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAmB,EAAE,UAA0B,eAAe;IACtF,OAAO,CACL,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ;QACjC,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI;QACzB,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CACtC,CAAC;AACJ,CAAC"}
|