@stratusagent/agents 0.11.4 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/define.d.ts +22 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +64 -0
- package/dist/define.js.map +1 -0
- package/dist/frontmatter.d.ts +65 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +260 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/identity.d.ts +139 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +259 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +11 -654
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1641
- package/dist/index.js.map +1 -1
- package/dist/router.d.ts +18 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +44 -0
- package/dist/router.js.map +1 -0
- package/dist/schedules.d.ts +163 -0
- package/dist/schedules.d.ts.map +1 -0
- package/dist/schedules.js +215 -0
- package/dist/schedules.js.map +1 -0
- package/dist/skills.d.ts +135 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +167 -0
- package/dist/skills.js.map +1 -0
- package/dist/soul.d.ts +44 -0
- package/dist/soul.d.ts.map +1 -0
- package/dist/soul.js +98 -0
- package/dist/soul.js.map +1 -0
- package/dist/tools/delegate.d.ts +93 -0
- package/dist/tools/delegate.d.ts.map +1 -0
- package/dist/tools/delegate.js +223 -0
- package/dist/tools/delegate.js.map +1 -0
- package/dist/tools/gateway-only.d.ts +19 -0
- package/dist/tools/gateway-only.d.ts.map +1 -0
- package/dist/tools/gateway-only.js +29 -0
- package/dist/tools/gateway-only.js.map +1 -0
- package/dist/tools/memory.d.ts +51 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +306 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/message.d.ts +26 -0
- package/dist/tools/message.d.ts.map +1 -0
- package/dist/tools/message.js +46 -0
- package/dist/tools/message.js.map +1 -0
- package/dist/tools/schedule.d.ts +20 -0
- package/dist/tools/schedule.d.ts.map +1 -0
- package/dist/tools/schedule.js +146 -0
- package/dist/tools/schedule.js.map +1 -0
- package/package.json +2 -2
package/dist/skills.d.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { Skill } from '@stratusagent/core';
|
|
2
|
+
/**
|
|
3
|
+
* The shape a skill id is written in — the Agent Skills spec's rule for
|
|
4
|
+
* `name`, which is also the directory name: lowercase letters and digits
|
|
5
|
+
* in hyphen-separated runs (`web-research`), at most 64 characters, no
|
|
6
|
+
* leading, trailing, or doubled hyphen. One pattern for the manifest's
|
|
7
|
+
* declared ids, the operator directory's folder names, and install-time
|
|
8
|
+
* validation — two copies would drift into two answers to what a valid
|
|
9
|
+
* id is.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SKILL_ID_PATTERN: RegExp;
|
|
12
|
+
/** The spec's ceiling on `name`, and so on a skill id. */
|
|
13
|
+
export declare const SKILL_ID_MAX_LENGTH = 64;
|
|
14
|
+
export declare const isValidSkillId: (id: string) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Whether an id that is already on this machine — a directory under
|
|
17
|
+
* `~/.stratus/skills/`, a plugin manifest's declared id — is served.
|
|
18
|
+
* Wider than `isValidSkillId` on purpose: the spec's rule arrived after
|
|
19
|
+
* some of these were written, and tightening the *loader* would silently
|
|
20
|
+
* drop an enabled procedure from an agent on upgrade. Installing and
|
|
21
|
+
* validating use the strict rule; loading uses this one, and warns.
|
|
22
|
+
*/
|
|
23
|
+
export declare const isLoadableSkillId: (id: string) => boolean;
|
|
24
|
+
/** What a skill id refusal says, everywhere one is refused. */
|
|
25
|
+
export declare const SKILL_ID_RULE = "Skill ids are lowercase letters, digits, and single hyphens (web-research), at most 64 characters.";
|
|
26
|
+
/** The spec's ceiling on `description`. */
|
|
27
|
+
export declare const SKILL_DESCRIPTION_MAX_LENGTH = 1024;
|
|
28
|
+
/** The spec's ceiling on `compatibility`. */
|
|
29
|
+
export declare const SKILL_COMPATIBILITY_MAX_LENGTH = 500;
|
|
30
|
+
/**
|
|
31
|
+
* A parsed `SKILL.md`: the one-line identity that reaches the system
|
|
32
|
+
* prompt, and the body that only ever travels through `skill.read`.
|
|
33
|
+
*/
|
|
34
|
+
export interface ParsedSkillDocument {
|
|
35
|
+
/**
|
|
36
|
+
* The skill's name — under the spec, its id, and equal to its directory
|
|
37
|
+
* name. Optional here because loading stays tolerant of what is already
|
|
38
|
+
* installed; the registered skill falls back to its id.
|
|
39
|
+
*/
|
|
40
|
+
name?: string;
|
|
41
|
+
/**
|
|
42
|
+
* When to reach for this skill — what routing runs on, so it earns its
|
|
43
|
+
* place by saying when, not what the body contains.
|
|
44
|
+
*/
|
|
45
|
+
description: string;
|
|
46
|
+
/** The spec's `license`: a name, or a bundled file. Informational. */
|
|
47
|
+
license?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The spec's `compatibility`: what the skill needs from its environment,
|
|
50
|
+
* in prose — for the operator installing it, since nothing here can act
|
|
51
|
+
* on it.
|
|
52
|
+
*/
|
|
53
|
+
compatibility?: string;
|
|
54
|
+
/** The spec's `metadata:` map, verbatim — every value a string. */
|
|
55
|
+
metadata?: Record<string, string>;
|
|
56
|
+
/** `metadata.version`, or the legacy top-level key. Informational. */
|
|
57
|
+
version?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Toolset globs the procedure expects (`browser.*`), from
|
|
60
|
+
* `metadata.requires` (space-separated) or the legacy top-level list.
|
|
61
|
+
* Advisory — see `Skill.requires`.
|
|
62
|
+
*/
|
|
63
|
+
requires?: string[];
|
|
64
|
+
/**
|
|
65
|
+
* Top-level keys outside the spec, in file order — the legacy Stratus
|
|
66
|
+
* keys and other hosts' fields alike. What validation warns about.
|
|
67
|
+
*/
|
|
68
|
+
unknownKeys: string[];
|
|
69
|
+
body: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Parse a `SKILL.md` — the same frontmatter dialect souls use (`key: value`
|
|
73
|
+
* scalars, block lists), plus the spec's `metadata:` map. The body is the
|
|
74
|
+
* procedure itself, markdown, untouched.
|
|
75
|
+
*
|
|
76
|
+
* `description` is required: it is the only thing the model sees before
|
|
77
|
+
* deciding to load the body, and a skill without one is unreachable by the
|
|
78
|
+
* mechanism that makes skills cheap. Everything the spec constrains beyond
|
|
79
|
+
* presence — the name rule, the length ceilings — is
|
|
80
|
+
* `validateSkillDocument`'s, so that loading what is already installed
|
|
81
|
+
* stays lenient while installing is strict.
|
|
82
|
+
*/
|
|
83
|
+
export declare const parseSkillDocument: (source: string) => ParsedSkillDocument;
|
|
84
|
+
export interface ValidateSkillDocumentOptions {
|
|
85
|
+
/**
|
|
86
|
+
* The directory the skill sits in (its basename), which the spec
|
|
87
|
+
* requires `name` to equal. Omit where the directory is circumstance
|
|
88
|
+
* rather than identity — a repository whose root is the skill, checked
|
|
89
|
+
* out wherever git put it.
|
|
90
|
+
*/
|
|
91
|
+
directoryName?: string;
|
|
92
|
+
/**
|
|
93
|
+
* What to suggest when `name` is missing — the directory name, or for a
|
|
94
|
+
* root skill the repository's. Only ever read for the error text.
|
|
95
|
+
*/
|
|
96
|
+
suggestedName?: string;
|
|
97
|
+
}
|
|
98
|
+
/** What `validateSkillDocument` found: errors refuse an install, warnings ride along. */
|
|
99
|
+
export interface SkillValidation {
|
|
100
|
+
errors: string[];
|
|
101
|
+
warnings: string[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check a parsed `SKILL.md` against the Agent Skills spec — the checks
|
|
105
|
+
* `skills-ref validate` runs, so a skill that passes here passes there:
|
|
106
|
+
* `name` present, shaped like an id, equal to the directory name;
|
|
107
|
+
* `description` and `compatibility` under their ceilings. Errors are what
|
|
108
|
+
* refuses an install. Top-level keys the spec does not define are
|
|
109
|
+
* warnings, not errors: the reference validator refuses them, but the
|
|
110
|
+
* ecosystem's skills carry other hosts' fields routinely, and refusing a
|
|
111
|
+
* skill over a field that changes nothing here fails the whole point of
|
|
112
|
+
* conforming. The legacy Stratus keys get their own warning, naming the
|
|
113
|
+
* `metadata:` form that ports.
|
|
114
|
+
*
|
|
115
|
+
* Loading never calls this — an installed skill keeps loading whatever
|
|
116
|
+
* the spec says today. Installing always does.
|
|
117
|
+
*/
|
|
118
|
+
export declare const validateSkillDocument: (document: ParsedSkillDocument, options?: ValidateSkillDocumentOptions) => SkillValidation;
|
|
119
|
+
export interface LazySkillInput {
|
|
120
|
+
/** The id the skill registers under — qualified for a plugin's skill. */
|
|
121
|
+
id: string;
|
|
122
|
+
/** The parsed document, from the load-time read that validated the file. */
|
|
123
|
+
document: ParsedSkillDocument;
|
|
124
|
+
/** Re-read the file's source. Called on demand; the registry caches. */
|
|
125
|
+
read: () => Promise<string>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A `Skill` whose body stays on disk until somebody asks. The identity
|
|
129
|
+
* comes from the load-time parse (which is also what validated the file);
|
|
130
|
+
* `load()` re-reads rather than closing over the body, so an
|
|
131
|
+
* enabled-but-unused skill costs its description line and nothing else —
|
|
132
|
+
* in the prompt and in memory.
|
|
133
|
+
*/
|
|
134
|
+
export declare const createLazySkill: ({ id, document, read }: LazySkillInput) => Skill;
|
|
135
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAGhD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,QAA+B,CAAC;AAE7D,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,eAAO,MAAM,cAAc,GAAI,IAAI,MAAM,KAAG,OACmB,CAAC;AAOhE;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,KAAG,OAA2C,CAAC;AAE3F,+DAA+D;AAC/D,eAAO,MAAM,aAAa,uGAC4E,CAAC;AAEvG,2CAA2C;AAC3C,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,6CAA6C;AAC7C,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAsBlD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,mBAyCnD,CAAC;AAEF,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,GAChC,UAAU,mBAAmB,EAC7B,UAAS,4BAAiC,KACzC,eAmDF,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,wEAAwE;IACxE,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,wBAAwB,cAAc,KAAG,KAMvE,CAAC"}
|
package/dist/skills.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { parseFrontmatterLines, extractFrontmatter } from "./frontmatter.js";
|
|
2
|
+
/**
|
|
3
|
+
* The shape a skill id is written in — the Agent Skills spec's rule for
|
|
4
|
+
* `name`, which is also the directory name: lowercase letters and digits
|
|
5
|
+
* in hyphen-separated runs (`web-research`), at most 64 characters, no
|
|
6
|
+
* leading, trailing, or doubled hyphen. One pattern for the manifest's
|
|
7
|
+
* declared ids, the operator directory's folder names, and install-time
|
|
8
|
+
* validation — two copies would drift into two answers to what a valid
|
|
9
|
+
* id is.
|
|
10
|
+
*/
|
|
11
|
+
export const SKILL_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
12
|
+
/** The spec's ceiling on `name`, and so on a skill id. */
|
|
13
|
+
export const SKILL_ID_MAX_LENGTH = 64;
|
|
14
|
+
export const isValidSkillId = (id) => id.length <= SKILL_ID_MAX_LENGTH && SKILL_ID_PATTERN.test(id);
|
|
15
|
+
// The rule before the spec's: any lowercase kebab-ish run, doubled and
|
|
16
|
+
// trailing hyphens and all, no length cap. What a directory or manifest
|
|
17
|
+
// id that loaded yesterday was checked against.
|
|
18
|
+
const LEGACY_SKILL_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
19
|
+
/**
|
|
20
|
+
* Whether an id that is already on this machine — a directory under
|
|
21
|
+
* `~/.stratus/skills/`, a plugin manifest's declared id — is served.
|
|
22
|
+
* Wider than `isValidSkillId` on purpose: the spec's rule arrived after
|
|
23
|
+
* some of these were written, and tightening the *loader* would silently
|
|
24
|
+
* drop an enabled procedure from an agent on upgrade. Installing and
|
|
25
|
+
* validating use the strict rule; loading uses this one, and warns.
|
|
26
|
+
*/
|
|
27
|
+
export const isLoadableSkillId = (id) => LEGACY_SKILL_ID_PATTERN.test(id);
|
|
28
|
+
/** What a skill id refusal says, everywhere one is refused. */
|
|
29
|
+
export const SKILL_ID_RULE = 'Skill ids are lowercase letters, digits, and single hyphens (web-research), at most 64 characters.';
|
|
30
|
+
/** The spec's ceiling on `description`. */
|
|
31
|
+
export const SKILL_DESCRIPTION_MAX_LENGTH = 1024;
|
|
32
|
+
/** The spec's ceiling on `compatibility`. */
|
|
33
|
+
export const SKILL_COMPATIBILITY_MAX_LENGTH = 500;
|
|
34
|
+
// The frontmatter keys the Agent Skills spec defines. Everything else at
|
|
35
|
+
// the top level belongs to some other host — read past, and reported by
|
|
36
|
+
// `validateSkillDocument`. `allowed-tools` is read so it is not reported,
|
|
37
|
+
// and then deliberately unused: it is another host's pre-approval list,
|
|
38
|
+
// and here the two gates (a trusted config, a soul's allowlist) are the
|
|
39
|
+
// only things that grant a tool.
|
|
40
|
+
const SKILL_SPEC_KEYS = ['name', 'description', 'license', 'compatibility', 'metadata', 'allowed-tools'];
|
|
41
|
+
// `version` and `requires` at the top level are the pre-spec Stratus form;
|
|
42
|
+
// the spec keeps host extensions under `metadata:`, and that is where a
|
|
43
|
+
// skill written today puts them. The old form still reads, so an installed
|
|
44
|
+
// skill keeps working — and validation says which form it found.
|
|
45
|
+
const SKILL_SCALAR_KEYS = ['name', 'description', 'license', 'compatibility', 'allowed-tools', 'version'];
|
|
46
|
+
const SKILL_LIST_KEYS = ['requires'];
|
|
47
|
+
const SKILL_MAP_KEYS = ['metadata'];
|
|
48
|
+
const SKILL_LEGACY_KEYS = ['version', 'requires'];
|
|
49
|
+
/**
|
|
50
|
+
* Parse a `SKILL.md` — the same frontmatter dialect souls use (`key: value`
|
|
51
|
+
* scalars, block lists), plus the spec's `metadata:` map. The body is the
|
|
52
|
+
* procedure itself, markdown, untouched.
|
|
53
|
+
*
|
|
54
|
+
* `description` is required: it is the only thing the model sees before
|
|
55
|
+
* deciding to load the body, and a skill without one is unreachable by the
|
|
56
|
+
* mechanism that makes skills cheap. Everything the spec constrains beyond
|
|
57
|
+
* presence — the name rule, the length ceilings — is
|
|
58
|
+
* `validateSkillDocument`'s, so that loading what is already installed
|
|
59
|
+
* stays lenient while installing is strict.
|
|
60
|
+
*/
|
|
61
|
+
export const parseSkillDocument = (source) => {
|
|
62
|
+
const { lines, body } = extractFrontmatter(source, 'skill');
|
|
63
|
+
if (!lines) {
|
|
64
|
+
throw new Error('Skill file has no frontmatter. A SKILL.md starts with --- and needs at least a description.');
|
|
65
|
+
}
|
|
66
|
+
const { scalars, lists, maps, unknownKeys } = parseFrontmatterLines(lines, {
|
|
67
|
+
kind: 'skill',
|
|
68
|
+
scalarKeys: SKILL_SCALAR_KEYS,
|
|
69
|
+
listKeys: SKILL_LIST_KEYS,
|
|
70
|
+
mapKeys: SKILL_MAP_KEYS,
|
|
71
|
+
// Skills travel the wider agent-skills ecosystem (skills.sh and the
|
|
72
|
+
// registries behind it), whose frontmatter carries fields other hosts
|
|
73
|
+
// own. Those are metadata to skip, not defects to refuse — see
|
|
74
|
+
// FrontmatterShape.tolerant, and note souls do NOT set this.
|
|
75
|
+
tolerant: true,
|
|
76
|
+
});
|
|
77
|
+
const description = scalars.description;
|
|
78
|
+
if (!description) {
|
|
79
|
+
throw new Error('Skill frontmatter has no "description". The description is what an agent routes on — say when to reach for this skill.');
|
|
80
|
+
}
|
|
81
|
+
const metadata = maps.metadata;
|
|
82
|
+
const version = metadata?.version ?? scalars.version;
|
|
83
|
+
const requires = metadata?.requires !== undefined
|
|
84
|
+
? metadata.requires.split(/\s+/).filter((entry) => entry.length > 0)
|
|
85
|
+
: lists.requires;
|
|
86
|
+
// The legacy keys are read, and still not the spec's: a validator names
|
|
87
|
+
// them so a skill written here can be moved to the form that ports.
|
|
88
|
+
const legacy = SKILL_LEGACY_KEYS.filter((key) => (key === 'requires' ? lists.requires : scalars[key]) !== undefined);
|
|
89
|
+
return {
|
|
90
|
+
...(scalars.name ? { name: scalars.name } : {}),
|
|
91
|
+
description,
|
|
92
|
+
...(scalars.license ? { license: scalars.license } : {}),
|
|
93
|
+
...(scalars.compatibility ? { compatibility: scalars.compatibility } : {}),
|
|
94
|
+
...(metadata ? { metadata } : {}),
|
|
95
|
+
...(version ? { version } : {}),
|
|
96
|
+
...(requires && requires.length > 0 ? { requires } : {}),
|
|
97
|
+
unknownKeys: [...legacy, ...unknownKeys.filter((key) => !SKILL_SPEC_KEYS.includes(key))],
|
|
98
|
+
body: body.trim(),
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
const characterCount = (text) => Array.from(text).length;
|
|
102
|
+
/**
|
|
103
|
+
* Check a parsed `SKILL.md` against the Agent Skills spec — the checks
|
|
104
|
+
* `skills-ref validate` runs, so a skill that passes here passes there:
|
|
105
|
+
* `name` present, shaped like an id, equal to the directory name;
|
|
106
|
+
* `description` and `compatibility` under their ceilings. Errors are what
|
|
107
|
+
* refuses an install. Top-level keys the spec does not define are
|
|
108
|
+
* warnings, not errors: the reference validator refuses them, but the
|
|
109
|
+
* ecosystem's skills carry other hosts' fields routinely, and refusing a
|
|
110
|
+
* skill over a field that changes nothing here fails the whole point of
|
|
111
|
+
* conforming. The legacy Stratus keys get their own warning, naming the
|
|
112
|
+
* `metadata:` form that ports.
|
|
113
|
+
*
|
|
114
|
+
* Loading never calls this — an installed skill keeps loading whatever
|
|
115
|
+
* the spec says today. Installing always does.
|
|
116
|
+
*/
|
|
117
|
+
export const validateSkillDocument = (document, options = {}) => {
|
|
118
|
+
const errors = [];
|
|
119
|
+
const warnings = [];
|
|
120
|
+
if (document.name === undefined) {
|
|
121
|
+
const suggestion = options.suggestedName ?? options.directoryName;
|
|
122
|
+
errors.push(`frontmatter has no "name". The Agent Skills spec requires one, equal to the directory name${suggestion !== undefined ? ` — add: name: ${suggestion}` : ''}.`);
|
|
123
|
+
}
|
|
124
|
+
else if (!isValidSkillId(document.name)) {
|
|
125
|
+
errors.push(`name ${JSON.stringify(document.name)} is not a skill id. ${SKILL_ID_RULE}`);
|
|
126
|
+
}
|
|
127
|
+
else if (options.directoryName !== undefined && document.name !== options.directoryName) {
|
|
128
|
+
errors.push(`name ${JSON.stringify(document.name)} does not match the directory name ${JSON.stringify(options.directoryName)}. The spec requires the two to agree — rename one.`);
|
|
129
|
+
}
|
|
130
|
+
// Characters, as the spec and its Python reference count them — code
|
|
131
|
+
// points, not the UTF-16 units `.length` reports, which would count an
|
|
132
|
+
// emoji twice and refuse a description the reference validator passes.
|
|
133
|
+
const descriptionLength = characterCount(document.description);
|
|
134
|
+
if (descriptionLength > SKILL_DESCRIPTION_MAX_LENGTH) {
|
|
135
|
+
errors.push(`description is ${descriptionLength} characters, past the spec's ceiling of ${SKILL_DESCRIPTION_MAX_LENGTH}. Say when to reach for the skill, and move the rest into the body.`);
|
|
136
|
+
}
|
|
137
|
+
const compatibilityLength = document.compatibility !== undefined ? characterCount(document.compatibility) : 0;
|
|
138
|
+
if (compatibilityLength > SKILL_COMPATIBILITY_MAX_LENGTH) {
|
|
139
|
+
errors.push(`compatibility is ${compatibilityLength} characters, past the spec's ceiling of ${SKILL_COMPATIBILITY_MAX_LENGTH}.`);
|
|
140
|
+
}
|
|
141
|
+
const legacy = document.unknownKeys.filter((key) => SKILL_LEGACY_KEYS.includes(key));
|
|
142
|
+
const foreign = document.unknownKeys.filter((key) => !SKILL_LEGACY_KEYS.includes(key));
|
|
143
|
+
for (const key of legacy) {
|
|
144
|
+
warnings.push(key === 'requires'
|
|
145
|
+
? 'top-level "requires" is the pre-spec Stratus form, and the reference validator refuses it. Write it as metadata.requires, one space-separated string: "browser.* fs.read".'
|
|
146
|
+
: 'top-level "version" is the pre-spec Stratus form, and the reference validator refuses it. Write it as metadata.version.');
|
|
147
|
+
}
|
|
148
|
+
if (foreign.length > 0) {
|
|
149
|
+
warnings.push(`frontmatter key${foreign.length > 1 ? 's' : ''} outside the Agent Skills spec: ${foreign.map((key) => JSON.stringify(key)).join(', ')}. Another host's; ignored here, and the reference validator refuses ${foreign.length > 1 ? 'them' : 'it'}.`);
|
|
150
|
+
}
|
|
151
|
+
return { errors, warnings };
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* A `Skill` whose body stays on disk until somebody asks. The identity
|
|
155
|
+
* comes from the load-time parse (which is also what validated the file);
|
|
156
|
+
* `load()` re-reads rather than closing over the body, so an
|
|
157
|
+
* enabled-but-unused skill costs its description line and nothing else —
|
|
158
|
+
* in the prompt and in memory.
|
|
159
|
+
*/
|
|
160
|
+
export const createLazySkill = ({ id, document, read }) => ({
|
|
161
|
+
id,
|
|
162
|
+
name: document.name ?? id,
|
|
163
|
+
description: document.description,
|
|
164
|
+
...(document.requires ? { requires: document.requires } : {}),
|
|
165
|
+
load: async () => parseSkillDocument(await read()).body,
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
|
package/dist/soul.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type AgentDefinition } from '@stratusagent/core';
|
|
2
|
+
/**
|
|
3
|
+
* Whether `agent` may delegate to the agent with id `targetId`. Exact ids
|
|
4
|
+
* or `*`; no namespace globs, because agent ids have no namespaces. Omitted
|
|
5
|
+
* is nobody — see `AgentDefinition.delegates`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const isDelegateAllowed: (agent: Pick<AgentDefinition, "delegates">, targetId: string) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* A parsed soul file: the agent it defines plus optional runtime hints.
|
|
10
|
+
* Souls are markdown with frontmatter — the frontmatter carries structured
|
|
11
|
+
* identity (name, tools, credentials, provider, model) and the body is the
|
|
12
|
+
* persona itself, written in prose.
|
|
13
|
+
*/
|
|
14
|
+
export interface ParsedSoul {
|
|
15
|
+
agent: AgentDefinition;
|
|
16
|
+
/** Provider the soul prefers (e.g. "anthropic"). Runtimes may override. */
|
|
17
|
+
provider?: string;
|
|
18
|
+
/** Model the soul prefers (e.g. "claude-opus-5"). Runtimes may override. */
|
|
19
|
+
model?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ParseSoulOptions {
|
|
22
|
+
/** Seed for deterministic identity generation when the soul has no name. */
|
|
23
|
+
seed?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The soul edit that grants one delegate, as the refusal suggests it. The
|
|
27
|
+
* inline form, `delegates: [a, "b, c"]`, quoted when the inline parser
|
|
28
|
+
* would otherwise split or unquote the id, in whichever quote it does not
|
|
29
|
+
* contain — and the block form when the id holds both quotes, since no
|
|
30
|
+
* inline spelling of `a"',b` reads back as one entry, while a block line
|
|
31
|
+
* is never split and is unquoted only for matching outer quotes, which
|
|
32
|
+
* {@link writeScalar} guards. Rendered this carefully because
|
|
33
|
+
* `delegates: [foo,bar]` is a grant to two agents and a refusal of the
|
|
34
|
+
* one the message was about.
|
|
35
|
+
*/
|
|
36
|
+
export declare const suggestedDelegatesEdit: (value: string) => string;
|
|
37
|
+
/**
|
|
38
|
+
* Parse a soul file (markdown with optional frontmatter) into an agent
|
|
39
|
+
* definition. The body becomes the agent's instructions; a missing name is
|
|
40
|
+
* generated, so the smallest possible soul is just prose.
|
|
41
|
+
*/
|
|
42
|
+
export declare const parseSoul: (source: string, options?: ParseSoulOptions) => ParsedSoul;
|
|
43
|
+
export declare const formatSoul: (soul: ParsedSoul) => string;
|
|
44
|
+
//# sourceMappingURL=soul.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"soul.d.ts","sourceRoot":"","sources":["../src/soul.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUxF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,UAAU,MAAM,KAAG,OAClB,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,KAAG,MAWtD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAS,gBAAqB,KAAG,UAkC1E,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,UAAU,KAAG,MA8B7C,CAAC"}
|
package/dist/soul.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { isListensMode, LISTENS_MODES } from '@stratusagent/core';
|
|
2
|
+
import { defineAgent } from "./define.js";
|
|
3
|
+
import { unquote, parseFrontmatterLines, extractFrontmatter, writeScalar, } from "./frontmatter.js";
|
|
4
|
+
/**
|
|
5
|
+
* Whether `agent` may delegate to the agent with id `targetId`. Exact ids
|
|
6
|
+
* or `*`; no namespace globs, because agent ids have no namespaces. Omitted
|
|
7
|
+
* is nobody — see `AgentDefinition.delegates`.
|
|
8
|
+
*/
|
|
9
|
+
export const isDelegateAllowed = (agent, targetId) => (agent.delegates ?? []).some((entry) => entry === '*' || entry === targetId);
|
|
10
|
+
const SOUL_SCALAR_KEYS = ['name', 'id', 'provider', 'model', 'listens'];
|
|
11
|
+
const SOUL_LIST_KEYS = ['tools', 'skills', 'credentials', 'delegates'];
|
|
12
|
+
/**
|
|
13
|
+
* The soul edit that grants one delegate, as the refusal suggests it. The
|
|
14
|
+
* inline form, `delegates: [a, "b, c"]`, quoted when the inline parser
|
|
15
|
+
* would otherwise split or unquote the id, in whichever quote it does not
|
|
16
|
+
* contain — and the block form when the id holds both quotes, since no
|
|
17
|
+
* inline spelling of `a"',b` reads back as one entry, while a block line
|
|
18
|
+
* is never split and is unquoted only for matching outer quotes, which
|
|
19
|
+
* {@link writeScalar} guards. Rendered this carefully because
|
|
20
|
+
* `delegates: [foo,bar]` is a grant to two agents and a refusal of the
|
|
21
|
+
* one the message was about.
|
|
22
|
+
*/
|
|
23
|
+
export const suggestedDelegatesEdit = (value) => {
|
|
24
|
+
if (!/[,"'\s]/.test(value) && unquote(value) === value) {
|
|
25
|
+
return `delegates: [${value}]`;
|
|
26
|
+
}
|
|
27
|
+
if (!value.includes('"')) {
|
|
28
|
+
return `delegates: ["${value}"]`;
|
|
29
|
+
}
|
|
30
|
+
if (!value.includes("'")) {
|
|
31
|
+
return `delegates: ['${value}']`;
|
|
32
|
+
}
|
|
33
|
+
return `a delegates: list with the line "- ${writeScalar(value)}"`;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Parse a soul file (markdown with optional frontmatter) into an agent
|
|
37
|
+
* definition. The body becomes the agent's instructions; a missing name is
|
|
38
|
+
* generated, so the smallest possible soul is just prose.
|
|
39
|
+
*/
|
|
40
|
+
export const parseSoul = (source, options = {}) => {
|
|
41
|
+
const { lines, body } = extractFrontmatter(source, 'soul');
|
|
42
|
+
const { scalars, lists } = lines
|
|
43
|
+
? parseFrontmatterLines(lines, { kind: 'soul', scalarKeys: SOUL_SCALAR_KEYS, listKeys: SOUL_LIST_KEYS })
|
|
44
|
+
: { scalars: {}, lists: {}, maps: {}, unknownKeys: [] };
|
|
45
|
+
const instructions = body.trim();
|
|
46
|
+
// Strict, like every soul key: a misspelled mode would otherwise load as
|
|
47
|
+
// the default, and an agent that answers every reply when it was meant
|
|
48
|
+
// to judge is the failure this file is read to prevent.
|
|
49
|
+
if (scalars.listens !== undefined && !isListensMode(scalars.listens)) {
|
|
50
|
+
throw new Error(`Soul frontmatter listens: ${JSON.stringify(scalars.listens)} is not a listening mode; use one of ${LISTENS_MODES.join(', ')}.`);
|
|
51
|
+
}
|
|
52
|
+
const agent = defineAgent({
|
|
53
|
+
...(scalars.name ? { name: scalars.name } : {}),
|
|
54
|
+
...(scalars.id ? { id: scalars.id } : {}),
|
|
55
|
+
...(instructions ? { instructions } : {}),
|
|
56
|
+
...(lists.tools ? { tools: lists.tools } : {}),
|
|
57
|
+
...(lists.skills ? { skills: lists.skills } : {}),
|
|
58
|
+
...(lists.credentials ? { credentials: lists.credentials } : {}),
|
|
59
|
+
...(lists.delegates ? { delegates: lists.delegates } : {}),
|
|
60
|
+
...(isListensMode(scalars.listens) ? { listens: scalars.listens } : {}),
|
|
61
|
+
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
agent,
|
|
65
|
+
...(scalars.provider ? { provider: scalars.provider } : {}),
|
|
66
|
+
...(scalars.model ? { model: scalars.model } : {}),
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export const formatSoul = (soul) => {
|
|
70
|
+
const lines = ['---', `name: ${writeScalar(soul.agent.name)}`, `id: ${writeScalar(soul.agent.id)}`];
|
|
71
|
+
if (soul.provider) {
|
|
72
|
+
lines.push(`provider: ${soul.provider}`);
|
|
73
|
+
}
|
|
74
|
+
if (soul.model) {
|
|
75
|
+
lines.push(`model: ${soul.model}`);
|
|
76
|
+
}
|
|
77
|
+
if (soul.agent.listens) {
|
|
78
|
+
lines.push(`listens: ${soul.agent.listens}`);
|
|
79
|
+
}
|
|
80
|
+
for (const [key, values] of [
|
|
81
|
+
['tools', soul.agent.tools],
|
|
82
|
+
['skills', soul.agent.skills],
|
|
83
|
+
['credentials', soul.agent.credentials],
|
|
84
|
+
['delegates', soul.agent.delegates],
|
|
85
|
+
]) {
|
|
86
|
+
if (values && values.length > 0) {
|
|
87
|
+
lines.push(`${key}:`);
|
|
88
|
+
for (const value of values) {
|
|
89
|
+
lines.push(` - ${writeScalar(value)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
lines.push('---', '');
|
|
94
|
+
lines.push(soul.agent.instructions ?? 'Describe who this agent is and how they talk.');
|
|
95
|
+
lines.push('');
|
|
96
|
+
return lines.join('\n');
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=soul.js.map
|
package/dist/soul.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"soul.js","sourceRoot":"","sources":["../src/soul.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { AgentRegistry, type AgentDefinition, type AgentRunner, type JsonObject, type Session, type Tool } from '@stratusagent/core';
|
|
2
|
+
export declare const DELEGATE_TOOL_NAME = "agent.delegate";
|
|
3
|
+
/**
|
|
4
|
+
* Metadata a delegated sub-session carries: which agent delegated, and the
|
|
5
|
+
* session at the root of the chain. Written by `agent.delegate` and read by
|
|
6
|
+
* the gateway's restart sweep, which is why the keys are named here rather
|
|
7
|
+
* than spelled twice — a sub-session's parent is a turn in some other
|
|
8
|
+
* process's memory, and after a restart nothing can consume its reply.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DELEGATED_BY_METADATA_KEY = "delegatedBy";
|
|
11
|
+
export declare const ROOT_SESSION_ID_METADATA_KEY = "rootSessionId";
|
|
12
|
+
export declare const DELEGATION_DEPTH_METADATA_KEY = "delegationDepth";
|
|
13
|
+
/**
|
|
14
|
+
* The segment `agent.delegate` mints into every sub-session's id —
|
|
15
|
+
* `<parent>:delegate:<agent>:<depth>:<suffix>`. The second half of what
|
|
16
|
+
* identifies a sub-session, beside the metadata above: the gateway refuses
|
|
17
|
+
* the metadata keys at its public door, but rows written before it did
|
|
18
|
+
* cannot be told apart by their metadata alone, and a caller who wrote
|
|
19
|
+
* `delegatedBy` onto a session of its own would not also have minted an
|
|
20
|
+
* id in this shape.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DELEGATED_SESSION_ID_MARKER = ":delegate:";
|
|
23
|
+
/**
|
|
24
|
+
* Whether this session is a delegated sub-session — one whose reply is
|
|
25
|
+
* consumed by a parent turn's `agent.delegate` call and by nothing else.
|
|
26
|
+
* Both halves are required: the metadata `agent.delegate` writes, and the
|
|
27
|
+
* id shape it mints.
|
|
28
|
+
*/
|
|
29
|
+
export declare const isDelegatedSession: (session: Pick<Session, "id" | "metadata">) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The id of the session whose `agent.delegate` call started this one, read
|
|
32
|
+
* off the id shape above — the text before the last marker, since a nested
|
|
33
|
+
* sub-session embeds its parent's id whole. Undefined for an id that was
|
|
34
|
+
* not minted that way.
|
|
35
|
+
*/
|
|
36
|
+
export declare const delegatingSessionIdOf: (sessionId: string) => string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The id of the `agent.delegate` call in `parent` that is still awaiting
|
|
39
|
+
* `child`, or undefined when none is.
|
|
40
|
+
*
|
|
41
|
+
* The one thing about a delegation nothing outside the runner can forge:
|
|
42
|
+
* a caller can name a session in the sub-session id shape and write the
|
|
43
|
+
* metadata keys, but only the runner writes assistant tool calls, and only
|
|
44
|
+
* a delegation in flight leaves one with no result behind it. Matched to
|
|
45
|
+
* the child and not merely counted, because a parent can be inside one
|
|
46
|
+
* delegation while an earlier sub-session of its — continued from outside
|
|
47
|
+
* under a version that kept the markers — is parked on something of its
|
|
48
|
+
* own. The call names its target and its prompt, and `agent.delegate`
|
|
49
|
+
* made the prompt the child's first user message. Read against the
|
|
50
|
+
* transcript order so a re-used call id cannot make a later call look
|
|
51
|
+
* answered.
|
|
52
|
+
*/
|
|
53
|
+
export declare const outstandingDelegationFor: (parent: Pick<Session, "messages">, child: Pick<Session, "agent" | "messages">) => string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* `metadata` with the delegation markers removed — what a sub-session
|
|
56
|
+
* carries once it has been addressed from outside. The delegation ended
|
|
57
|
+
* with the turn that awaited it; a conversation somebody continues on the
|
|
58
|
+
* same id afterwards is an ordinary one, and must not be closed as an
|
|
59
|
+
* orphan by a later restart.
|
|
60
|
+
*/
|
|
61
|
+
export declare const withoutDelegation: (metadata: JsonObject) => JsonObject;
|
|
62
|
+
/**
|
|
63
|
+
* Runs a delegated sub-session. A plain runner works when every agent
|
|
64
|
+
* shares one provider; a host with per-agent provider routing (the
|
|
65
|
+
* gateway) supplies its own dispatcher so the target runs on the
|
|
66
|
+
* target's resolved provider and credentials — never the delegator's.
|
|
67
|
+
*/
|
|
68
|
+
export type DelegateDispatch = (input: {
|
|
69
|
+
sessionId: string;
|
|
70
|
+
agent: AgentDefinition;
|
|
71
|
+
userMessage: string;
|
|
72
|
+
metadata: JsonObject;
|
|
73
|
+
/** The parent turn's abort signal — a cancelled parent cancels the delegated run too. */
|
|
74
|
+
signal?: AbortSignal;
|
|
75
|
+
}) => Promise<Session>;
|
|
76
|
+
export type DelegateToolOptions = {
|
|
77
|
+
registry: AgentRegistry;
|
|
78
|
+
/** Maximum delegation depth to stop orchestrator loops. Default 3. */
|
|
79
|
+
maxDepth?: number;
|
|
80
|
+
} & ({
|
|
81
|
+
runner: AgentRunner;
|
|
82
|
+
dispatch?: never;
|
|
83
|
+
} | {
|
|
84
|
+
dispatch: DelegateDispatch;
|
|
85
|
+
runner?: never;
|
|
86
|
+
});
|
|
87
|
+
/**
|
|
88
|
+
* The orchestrator primitive: a tool that runs another agent in its own
|
|
89
|
+
* sub-session (with that agent's memory, tool allowlist, and credentials)
|
|
90
|
+
* and returns its final reply as the tool result.
|
|
91
|
+
*/
|
|
92
|
+
export declare const createDelegateTool: ({ registry, runner, dispatch, maxDepth, }: DelegateToolOptions) => Tool;
|
|
93
|
+
//# sourceMappingURL=delegate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.d.ts","sourceRoot":"","sources":["../../src/tools/delegate.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAIb,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,IAAI,EACV,MAAM,oBAAoB,CAAC;AAG5B,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,gBAAgB,CAAC;AAEvD,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D,eAAO,MAAM,6BAA6B,oBAAoB,CAAC;AAE/D;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,eAAe,CAAC;AAExD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,UAAU,CAAC,KAAG,OAE1B,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,MAAM,KAAG,MAAM,GAAG,SAGlE,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,wBAAwB,GACnC,QAAQ,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EACjC,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAAC,KACzC,MAAM,GAAG,SA8BX,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,UAAU,KAAG,UAQxD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,UAAU,CAAC;IACrB,yFAAyF;IACzF,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvB,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,aAAa,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,CAAC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,gBAAgB,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAIjG;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,2CAKhC,mBAAmB,KAAG,IA6HxB,CAAC"}
|