agentfootprint 9.32.0 → 9.34.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/dist/adapters/hosting/firestoreSessions.js +813 -0
- package/dist/adapters/hosting/firestoreSessions.js.map +1 -0
- package/dist/core/agent/buildToolRegistry.js +1 -1
- package/dist/core/agent/buildToolRegistry.js.map +1 -1
- package/dist/core/agent/toolEffects.js +4 -10
- package/dist/core/agent/toolEffects.js.map +1 -1
- package/dist/core/slots/buildToolsSlot.js +2 -1
- package/dist/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/doors/skill-graph.js +109 -0
- package/dist/doors/skill-graph.js.map +1 -0
- package/dist/esm/adapters/hosting/firestoreSessions.d.ts +474 -0
- package/dist/esm/adapters/hosting/firestoreSessions.js +803 -0
- package/dist/esm/adapters/hosting/firestoreSessions.js.map +1 -0
- package/dist/esm/core/agent/buildToolRegistry.js +2 -2
- package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
- package/dist/esm/core/agent/toolEffects.d.ts +15 -7
- package/dist/esm/core/agent/toolEffects.js +2 -9
- package/dist/esm/core/agent/toolEffects.js.map +1 -1
- package/dist/esm/core/slots/buildToolsSlot.js +2 -1
- package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/doors/skill-graph.d.ts +70 -0
- package/dist/esm/doors/skill-graph.js +77 -0
- package/dist/esm/doors/skill-graph.js.map +1 -0
- package/dist/esm/hosting-providers.d.ts +22 -0
- package/dist/esm/hosting-providers.js +27 -0
- package/dist/esm/hosting-providers.js.map +1 -1
- package/dist/esm/lib/injection-engine/devWarn.d.ts +47 -0
- package/dist/esm/lib/injection-engine/devWarn.js +57 -0
- package/dist/esm/lib/injection-engine/devWarn.js.map +1 -0
- package/dist/esm/lib/injection-engine/devWarnHost.d.ts +16 -0
- package/dist/esm/lib/injection-engine/devWarnHost.js +19 -0
- package/dist/esm/lib/injection-engine/devWarnHost.js.map +1 -0
- package/dist/esm/lib/injection-engine/hostContract.d.ts +211 -0
- package/dist/esm/lib/injection-engine/hostContract.js +37 -0
- package/dist/esm/lib/injection-engine/hostContract.js.map +1 -0
- package/dist/esm/lib/injection-engine/index.d.ts +7 -2
- package/dist/esm/lib/injection-engine/index.js +18 -2
- package/dist/esm/lib/injection-engine/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraph.d.ts +3 -2
- package/dist/esm/lib/injection-engine/skillGraph.js +7 -12
- package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillIntent.js +4 -7
- package/dist/esm/lib/injection-engine/skillIntent.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillSteps.d.ts +18 -10
- package/dist/esm/lib/injection-engine/skillSteps.js +17 -12
- package/dist/esm/lib/injection-engine/skillSteps.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillToolDescriptors.d.ts +119 -0
- package/dist/esm/lib/injection-engine/skillToolDescriptors.js +182 -0
- package/dist/esm/lib/injection-engine/skillToolDescriptors.js.map +1 -0
- package/dist/esm/lib/injection-engine/skillTools.d.ts +41 -79
- package/dist/esm/lib/injection-engine/skillTools.js +61 -137
- package/dist/esm/lib/injection-engine/skillTools.js.map +1 -1
- package/dist/esm/lib/injection-engine/toolOutcome.d.ts +30 -0
- package/dist/esm/lib/injection-engine/toolOutcome.js +31 -0
- package/dist/esm/lib/injection-engine/toolOutcome.js.map +1 -0
- package/dist/esm/lib/injection-engine/types.d.ts +38 -14
- package/dist/esm/lib/injection-engine/types.js.map +1 -1
- package/dist/hosting-providers.js +34 -1
- package/dist/hosting-providers.js.map +1 -1
- package/dist/lib/injection-engine/devWarn.js +63 -0
- package/dist/lib/injection-engine/devWarn.js.map +1 -0
- package/dist/lib/injection-engine/devWarnHost.js +21 -0
- package/dist/lib/injection-engine/devWarnHost.js.map +1 -0
- package/dist/lib/injection-engine/hostContract.js +38 -0
- package/dist/lib/injection-engine/hostContract.js.map +1 -0
- package/dist/lib/injection-engine/index.js +23 -2
- package/dist/lib/injection-engine/index.js.map +1 -1
- package/dist/lib/injection-engine/skillGraph.js +7 -12
- package/dist/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/lib/injection-engine/skillIntent.js +4 -7
- package/dist/lib/injection-engine/skillIntent.js.map +1 -1
- package/dist/lib/injection-engine/skillSteps.js +19 -14
- package/dist/lib/injection-engine/skillSteps.js.map +1 -1
- package/dist/lib/injection-engine/skillToolDescriptors.js +187 -0
- package/dist/lib/injection-engine/skillToolDescriptors.js.map +1 -0
- package/dist/lib/injection-engine/skillTools.js +63 -138
- package/dist/lib/injection-engine/skillTools.js.map +1 -1
- package/dist/lib/injection-engine/toolOutcome.js +34 -0
- package/dist/lib/injection-engine/toolOutcome.js.map +1 -0
- package/dist/lib/injection-engine/types.js.map +1 -1
- package/dist/types/adapters/hosting/firestoreSessions.d.ts +475 -0
- package/dist/types/adapters/hosting/firestoreSessions.d.ts.map +1 -0
- package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -1
- package/dist/types/core/agent/toolEffects.d.ts +15 -7
- package/dist/types/core/agent/toolEffects.d.ts.map +1 -1
- package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
- package/dist/types/doors/skill-graph.d.ts +71 -0
- package/dist/types/doors/skill-graph.d.ts.map +1 -0
- package/dist/types/hosting-providers.d.ts +22 -0
- package/dist/types/hosting-providers.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/devWarn.d.ts +48 -0
- package/dist/types/lib/injection-engine/devWarn.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/devWarnHost.d.ts +17 -0
- package/dist/types/lib/injection-engine/devWarnHost.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/hostContract.d.ts +212 -0
- package/dist/types/lib/injection-engine/hostContract.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/index.d.ts +7 -2
- package/dist/types/lib/injection-engine/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraph.d.ts +3 -2
- package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillIntent.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillSteps.d.ts +18 -10
- package/dist/types/lib/injection-engine/skillSteps.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillToolDescriptors.d.ts +120 -0
- package/dist/types/lib/injection-engine/skillToolDescriptors.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/skillTools.d.ts +41 -79
- package/dist/types/lib/injection-engine/skillTools.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/toolOutcome.d.ts +31 -0
- package/dist/types/lib/injection-engine/toolOutcome.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/types.d.ts +38 -14
- package/dist/types/lib/injection-engine/types.d.ts.map +1 -1
- package/package.json +20 -2
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Skill-tool
|
|
3
|
-
* `
|
|
4
|
-
* `SkillRegistry.toTools()` (explicit composition path).
|
|
2
|
+
* Skill-tool ADAPTERS — the one place the graph's tool DESCRIPTIONS become
|
|
3
|
+
* agentfootprint `Tool`s.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* `list_skills`, `read_skill` and `skip_step` are described — name, schema,
|
|
6
|
+
* every sentence the model reads — by the pure skill-graph core
|
|
7
|
+
* (`skillToolDescriptors.ts`, `skillSteps.ts`). This module does the last
|
|
8
|
+
* step: hands each descriptor to `defineTool`. That split (9.34.0) is what
|
|
9
|
+
* keeps `read_skill`'s grammar, which is genuinely the graph's — the enum is
|
|
10
|
+
* the catalog, the description is the reachability offer, the result is what
|
|
11
|
+
* the model learns about the skill it activated — out of a module that has to
|
|
12
|
+
* import the framework's tool factory, and therefore out of everything that
|
|
13
|
+
* factory pulls in (artifacts, credentials, check-in, tool sessions).
|
|
10
14
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Both tool pairs work over the SAME catalog (a list of `Injection` skills),
|
|
16
|
+
* used by the Agent's auto-attach path AND by `SkillRegistry.toTools()`
|
|
17
|
+
* (explicit composition path). Pulling them out of `core/Agent.ts` removed
|
|
18
|
+
* the v2.4 duplication risk: the Agent auto-attaches its own `read_skill`,
|
|
19
|
+
* the registry builds a sibling — they MUST agree on schema + execute
|
|
20
|
+
* semantics, and now they cannot disagree because neither writes the words.
|
|
17
21
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
+
* Tool execute is identity-style (returns a confirmation string); the agent's
|
|
23
|
+
* tool-calls subflow inspects the tool name + args and updates
|
|
24
|
+
* `scope.activatedInjectionIds` so the next iteration's InjectionEngine sees
|
|
25
|
+
* the new activation.
|
|
26
|
+
*
|
|
27
|
+
* Zone: HOST. Importing `core/tools.js` here is the point of the file.
|
|
22
28
|
*/
|
|
23
29
|
import type { Tool } from '../../core/tools.js';
|
|
30
|
+
import { type ReadSkillOffer } from './skillToolDescriptors.js';
|
|
24
31
|
import type { Injection } from './types.js';
|
|
32
|
+
export type { ReadSkillOffer } from './skillToolDescriptors.js';
|
|
25
33
|
/**
|
|
26
34
|
* Build the `list_skills` tool — a no-arg tool that returns the
|
|
27
35
|
* registered skills as `{ id, description }[]`. Lets the LLM discover
|
|
@@ -34,68 +42,6 @@ import type { Injection } from './types.js';
|
|
|
34
42
|
* guard or filter undefined out of their tool list.
|
|
35
43
|
*/
|
|
36
44
|
export declare function buildListSkillsTool(skills: readonly Injection[]): Tool | undefined;
|
|
37
|
-
/**
|
|
38
|
-
* What the gate will ACTUALLY grant right now — the ids `read_skill` should be
|
|
39
|
-
* offering, as opposed to the ids it can dispatch (8.5.0).
|
|
40
|
-
*
|
|
41
|
-
* Without this the tool enumerated every registered skill while the skill-graph gate
|
|
42
|
-
* admitted only `reachableSkills(cursor) ∪ open`, so a route target the cursor cannot
|
|
43
|
-
* reach was advertised on every iteration and refused on every call. The model was
|
|
44
|
-
* being asked to choose from a menu the library knew it would reject.
|
|
45
|
-
*/
|
|
46
|
-
export interface ReadSkillOffer {
|
|
47
|
-
/**
|
|
48
|
-
* Ids the gate will grant from the current cursor. Omit when there is no
|
|
49
|
-
* graph — then the description is the plain catalog it has always been,
|
|
50
|
-
* minus anything {@link ReadSkillOffer.hiddenIds} removes.
|
|
51
|
-
*/
|
|
52
|
-
readonly grantable?: readonly string[];
|
|
53
|
-
/** Say the rest are refusable rather than hiding them. Hiding a skill it can see
|
|
54
|
-
* in `list_skills` (and in the enum) would just move the confusion; naming the
|
|
55
|
-
* boundary lets the model route around it in one step instead of guessing. */
|
|
56
|
-
readonly showRefusable?: boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Ids removed from the description ENTIRELY — not listed as reachable, not
|
|
59
|
-
* listed as refusable, not named at all (9.11.0).
|
|
60
|
-
*
|
|
61
|
-
* The opposite treatment from the graph's `shut` set above, and deliberately
|
|
62
|
-
* so. A graph refusal is about WHERE THE CURSOR IS: the skill exists for this
|
|
63
|
-
* caller, it is simply not reachable from here, so naming it lets the model
|
|
64
|
-
* route to it in one step. A hidden skill is about WHO IS ASKING: no cursor
|
|
65
|
-
* move makes it available, and naming it would tell a role about a capability
|
|
66
|
-
* it will never be allowed to use — leaking the shape of somebody else's
|
|
67
|
-
* permissions into this model's prompt.
|
|
68
|
-
*
|
|
69
|
-
* The ENUM keeps the full catalog either way (see below). Narrowing it would
|
|
70
|
-
* turn a policy refusal into a generic schema error, and the model would
|
|
71
|
-
* never read the policy's own message.
|
|
72
|
-
*/
|
|
73
|
-
readonly hiddenIds?: readonly string[];
|
|
74
|
-
/**
|
|
75
|
-
* Turn-start MENU (SG-C): when set, the description LEADS with these
|
|
76
|
-
* candidates (id + one-line description; advisory relevance %s beside
|
|
77
|
-
* near-tie candidates), names the cursor, and states STAY as a first-class
|
|
78
|
-
* option ("answer without calling read_skill to stay in '<cursor>'").
|
|
79
|
-
*
|
|
80
|
-
* Set only while the turn's menu verdict is outstanding (turn start, before
|
|
81
|
-
* any accepted pick) — the tools slot reads it off the SAME verdict the
|
|
82
|
-
* record carries, so the offer can never drift from `turn_routed.offered`.
|
|
83
|
-
* The enum stays the full catalog (the 8.5.0 law below — narrowing it would
|
|
84
|
-
* retire four honesty mechanisms), and {@link ReadSkillOffer.hiddenIds}
|
|
85
|
-
* filters menu rows exactly as it filters every other list: a role-hidden
|
|
86
|
-
* skill is never NAMED, menu or no menu.
|
|
87
|
-
*/
|
|
88
|
-
readonly menu?: {
|
|
89
|
-
readonly candidates: ReadonlyArray<{
|
|
90
|
-
readonly id: string;
|
|
91
|
-
readonly relevance?: number;
|
|
92
|
-
}>;
|
|
93
|
-
/** Names the cursor the STAY sentence refers to ("you are in billing"). */
|
|
94
|
-
readonly cursorId?: string;
|
|
95
|
-
/** STAY spelled out as a first-class option (mid-conversation menus). */
|
|
96
|
-
readonly stay?: boolean;
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
45
|
/**
|
|
100
46
|
* Build the `read_skill` tool — activates a skill for the next
|
|
101
47
|
* iteration. The LLM picks WHICH skill via the `id` argument.
|
|
@@ -123,6 +69,22 @@ export interface ReadSkillOffer {
|
|
|
123
69
|
* way. Omit it and the tool is byte-identical to what it has always been.
|
|
124
70
|
*/
|
|
125
71
|
export declare function buildReadSkillTool(skills: readonly Injection[], offer?: ReadSkillOffer): Tool | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Build the `skip_step` tool. Auto-attached to the dispatch registry when
|
|
74
|
+
* ≥1 registered skill declares steps (the `read_skill` auto-attach seam) —
|
|
75
|
+
* always dispatchable, but OFFERED (schema in the request) only while a
|
|
76
|
+
* stepped tenure is active and unfinished. Its execute returns a
|
|
77
|
+
* placeholder; the tool-calls stage overwrites the model-visible result
|
|
78
|
+
* with the authoritative sentence, exactly as the skill-graph gate
|
|
79
|
+
* overwrites `read_skill` refusals — bookkeeping lives where the batch
|
|
80
|
+
* order lives.
|
|
81
|
+
*
|
|
82
|
+
* Lived in `skillSteps.ts` through 9.33.x; moved here in 9.34.0 so that
|
|
83
|
+
* module — the procedure GRAMMAR — stops importing the tool factory. The
|
|
84
|
+
* sentences it speaks are still `skillSteps.ts`'s
|
|
85
|
+
* ({@link skipStepDescriptor}); only the wrapping moved.
|
|
86
|
+
*/
|
|
87
|
+
export declare function buildSkipStepTool(): Tool;
|
|
126
88
|
/**
|
|
127
89
|
* The pair returned by `SkillRegistry.toTools()`. Either entry may be
|
|
128
90
|
* undefined when the registry is empty. Consumers typically destructure:
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Skill-tool
|
|
3
|
-
* `
|
|
4
|
-
* `SkillRegistry.toTools()` (explicit composition path).
|
|
2
|
+
* Skill-tool ADAPTERS — the one place the graph's tool DESCRIPTIONS become
|
|
3
|
+
* agentfootprint `Tool`s.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* `list_skills`, `read_skill` and `skip_step` are described — name, schema,
|
|
6
|
+
* every sentence the model reads — by the pure skill-graph core
|
|
7
|
+
* (`skillToolDescriptors.ts`, `skillSteps.ts`). This module does the last
|
|
8
|
+
* step: hands each descriptor to `defineTool`. That split (9.34.0) is what
|
|
9
|
+
* keeps `read_skill`'s grammar, which is genuinely the graph's — the enum is
|
|
10
|
+
* the catalog, the description is the reachability offer, the result is what
|
|
11
|
+
* the model learns about the skill it activated — out of a module that has to
|
|
12
|
+
* import the framework's tool factory, and therefore out of everything that
|
|
13
|
+
* factory pulls in (artifacts, credentials, check-in, tool sessions).
|
|
10
14
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Both tool pairs work over the SAME catalog (a list of `Injection` skills),
|
|
16
|
+
* used by the Agent's auto-attach path AND by `SkillRegistry.toTools()`
|
|
17
|
+
* (explicit composition path). Pulling them out of `core/Agent.ts` removed
|
|
18
|
+
* the v2.4 duplication risk: the Agent auto-attaches its own `read_skill`,
|
|
19
|
+
* the registry builds a sibling — they MUST agree on schema + execute
|
|
20
|
+
* semantics, and now they cannot disagree because neither writes the words.
|
|
17
21
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
+
* Tool execute is identity-style (returns a confirmation string); the agent's
|
|
23
|
+
* tool-calls subflow inspects the tool name + args and updates
|
|
24
|
+
* `scope.activatedInjectionIds` so the next iteration's InjectionEngine sees
|
|
25
|
+
* the new activation.
|
|
26
|
+
*
|
|
27
|
+
* Zone: HOST. Importing `core/tools.js` here is the point of the file.
|
|
22
28
|
*/
|
|
23
29
|
import { defineTool } from '../../core/tools.js';
|
|
30
|
+
import { skipStepDescriptor } from './skillSteps.js';
|
|
31
|
+
import { listSkillsDescriptor, readSkillDescriptor, } from './skillToolDescriptors.js';
|
|
24
32
|
/**
|
|
25
33
|
* Build the `list_skills` tool — a no-arg tool that returns the
|
|
26
34
|
* registered skills as `{ id, description }[]`. Lets the LLM discover
|
|
@@ -33,80 +41,15 @@ import { defineTool } from '../../core/tools.js';
|
|
|
33
41
|
* guard or filter undefined out of their tool list.
|
|
34
42
|
*/
|
|
35
43
|
export function buildListSkillsTool(skills) {
|
|
36
|
-
|
|
44
|
+
const d = listSkillsDescriptor(skills);
|
|
45
|
+
if (!d)
|
|
37
46
|
return undefined;
|
|
38
|
-
// Capture a stable snapshot — the registry/agent calls this at
|
|
39
|
-
// build time, so the tool reflects the catalog as of registration.
|
|
40
|
-
const catalog = skills.map((s) => ({
|
|
41
|
-
id: s.id,
|
|
42
|
-
description: s.description ?? '(no description)',
|
|
43
|
-
}));
|
|
44
47
|
return defineTool({
|
|
45
|
-
name:
|
|
46
|
-
description:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
execute: () => {
|
|
50
|
-
// Return as a JSON-serialized string so the LLM can parse easily.
|
|
51
|
-
return JSON.stringify(catalog, null, 2);
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
/** Compose the tool description: one catalog, or the offer split in two. */
|
|
56
|
-
function describeOffer(allSkills, line, fullCatalog, offer) {
|
|
57
|
-
const tail = `Pass the skill's id. The skill's body becomes part of the system prompt and any ` +
|
|
58
|
-
`gated tools become available on the next call.`;
|
|
59
|
-
if (!offer) {
|
|
60
|
-
return `Activate a skill for the next iteration. Available skills:\n${fullCatalog}\n\n${tail}`;
|
|
61
|
-
}
|
|
62
|
-
// Hidden first, so nothing below can name one — the menu, the graph split,
|
|
63
|
-
// the "not reachable" list and the plain catalog all read from this.
|
|
64
|
-
const hidden = new Set(offer.hiddenIds ?? []);
|
|
65
|
-
const skills = hidden.size > 0 ? allSkills.filter((s) => !hidden.has(s.id)) : allSkills;
|
|
66
|
-
// The turn-start MENU leads (SG-C) — rendered from the turn verdict, ids
|
|
67
|
-
// resolved against the (hidden-filtered) catalog so an id this description
|
|
68
|
-
// may not name, or one that is not a skill here, is silently skipped rather
|
|
69
|
-
// than fabricated into a row.
|
|
70
|
-
const byId = new Map(skills.map((s) => [s.id, s]));
|
|
71
|
-
const menuRows = (offer.menu?.candidates ?? [])
|
|
72
|
-
.filter((c) => byId.has(c.id))
|
|
73
|
-
.map((c) => {
|
|
74
|
-
const pct = c.relevance !== undefined ? ` (relevance ~${Math.round(c.relevance * 100)}%)` : '';
|
|
75
|
-
return `${line(byId.get(c.id))}${pct}`;
|
|
48
|
+
name: d.name,
|
|
49
|
+
description: d.description,
|
|
50
|
+
inputSchema: d.inputSchema,
|
|
51
|
+
execute: (args) => d.execute(args),
|
|
76
52
|
});
|
|
77
|
-
const menuLead = offer.menu !== undefined && menuRows.length > 0
|
|
78
|
-
? `This turn needs a routing choice — no declared rule or intent decisively matched. ` +
|
|
79
|
-
`Closest candidates (advisory; an offline scorer ranked them and cannot see the ` +
|
|
80
|
-
`conversation):\n${menuRows.join('\n')}\n` +
|
|
81
|
-
(offer.menu.stay === true && offer.menu.cursorId !== undefined
|
|
82
|
-
? `You are in '${offer.menu.cursorId}'. Staying is a first-class option: answer ` +
|
|
83
|
-
`WITHOUT calling read_skill to stay in '${offer.menu.cursorId}'.\n\n`
|
|
84
|
-
: `Answering WITHOUT calling read_skill is also allowed.\n\n`)
|
|
85
|
-
: '';
|
|
86
|
-
if (offer.grantable === undefined) {
|
|
87
|
-
// No graph — the plain catalog, filtered. A role with nothing left is told
|
|
88
|
-
// plainly rather than handed an empty list to interpret.
|
|
89
|
-
return skills.length === 0
|
|
90
|
-
? `Activate a skill for the next iteration. No skills are available to you — ` +
|
|
91
|
-
`answer without one, or say what you are unable to do.\n\n${tail}`
|
|
92
|
-
: `${menuLead}Activate a skill for the next iteration. Available skills:\n${skills
|
|
93
|
-
.map(line)
|
|
94
|
-
.join('\n')}\n\n${tail}`;
|
|
95
|
-
}
|
|
96
|
-
const grantable = new Set(offer.grantable);
|
|
97
|
-
const open = skills.filter((s) => grantable.has(s.id));
|
|
98
|
-
const shut = skills.filter((s) => !grantable.has(s.id));
|
|
99
|
-
const parts = [
|
|
100
|
-
open.length > 0
|
|
101
|
-
? `Reachable from here:\n${open.map(line).join('\n')}`
|
|
102
|
-
: 'Nothing is reachable from here — answer with the skill you are in, or finish.',
|
|
103
|
-
];
|
|
104
|
-
if (offer.showRefusable !== false && shut.length > 0) {
|
|
105
|
-
parts.push(`Not reachable from here (read_skill for these will be refused):\n${shut
|
|
106
|
-
.map(line)
|
|
107
|
-
.join('\n')}`);
|
|
108
|
-
}
|
|
109
|
-
return `${menuLead}Activate a skill for the next iteration.\n\n${parts.join('\n\n')}\n\n${tail}`;
|
|
110
53
|
}
|
|
111
54
|
/**
|
|
112
55
|
* Build the `read_skill` tool — activates a skill for the next
|
|
@@ -135,57 +78,38 @@ function describeOffer(allSkills, line, fullCatalog, offer) {
|
|
|
135
78
|
* way. Omit it and the tool is byte-identical to what it has always been.
|
|
136
79
|
*/
|
|
137
80
|
export function buildReadSkillTool(skills, offer) {
|
|
138
|
-
|
|
81
|
+
const d = readSkillDescriptor(skills, offer);
|
|
82
|
+
if (!d)
|
|
139
83
|
return undefined;
|
|
140
|
-
const skillIds = skills.map((s) => s.id);
|
|
141
|
-
const line = (s) => ` - ${s.id}: ${s.description ?? '(no description)'}`;
|
|
142
|
-
const skillCatalog = skills.map(line).join('\n');
|
|
143
|
-
const byId = new Map();
|
|
144
|
-
for (const s of skills) {
|
|
145
|
-
const meta = s.metadata;
|
|
146
|
-
byId.set(s.id, {
|
|
147
|
-
body: s.inject.systemPrompt ?? '',
|
|
148
|
-
surfaceMode: meta?.surfaceMode ?? 'auto',
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
84
|
return defineTool({
|
|
152
|
-
name:
|
|
153
|
-
description:
|
|
154
|
-
inputSchema:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// - 'tool-only' / 'both' → return body verbatim (recency-first
|
|
181
|
-
// delivery; LLM sees it as the most recent tool result).
|
|
182
|
-
// - 'system-prompt' / 'auto' / unspecified → return confirmation
|
|
183
|
-
// only; body lands via system slot on the next iteration.
|
|
184
|
-
if ((entry.surfaceMode === 'tool-only' || entry.surfaceMode === 'both') && entry.body) {
|
|
185
|
-
return entry.body;
|
|
186
|
-
}
|
|
187
|
-
return `Skill '${id}' activated for the next iteration.`;
|
|
188
|
-
},
|
|
85
|
+
name: d.name,
|
|
86
|
+
description: d.description,
|
|
87
|
+
inputSchema: d.inputSchema,
|
|
88
|
+
execute: (args) => d.execute(args),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build the `skip_step` tool. Auto-attached to the dispatch registry when
|
|
93
|
+
* ≥1 registered skill declares steps (the `read_skill` auto-attach seam) —
|
|
94
|
+
* always dispatchable, but OFFERED (schema in the request) only while a
|
|
95
|
+
* stepped tenure is active and unfinished. Its execute returns a
|
|
96
|
+
* placeholder; the tool-calls stage overwrites the model-visible result
|
|
97
|
+
* with the authoritative sentence, exactly as the skill-graph gate
|
|
98
|
+
* overwrites `read_skill` refusals — bookkeeping lives where the batch
|
|
99
|
+
* order lives.
|
|
100
|
+
*
|
|
101
|
+
* Lived in `skillSteps.ts` through 9.33.x; moved here in 9.34.0 so that
|
|
102
|
+
* module — the procedure GRAMMAR — stops importing the tool factory. The
|
|
103
|
+
* sentences it speaks are still `skillSteps.ts`'s
|
|
104
|
+
* ({@link skipStepDescriptor}); only the wrapping moved.
|
|
105
|
+
*/
|
|
106
|
+
export function buildSkipStepTool() {
|
|
107
|
+
const d = skipStepDescriptor();
|
|
108
|
+
return defineTool({
|
|
109
|
+
name: d.name,
|
|
110
|
+
description: d.description,
|
|
111
|
+
inputSchema: d.inputSchema,
|
|
112
|
+
execute: (args) => d.execute(args),
|
|
189
113
|
});
|
|
190
114
|
}
|
|
191
115
|
//# sourceMappingURL=skillTools.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skillTools.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/skillTools.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"skillTools.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/skillTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,2BAA2B,CAAC;AAOnC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA4B;IAC9D,MAAM,CAAC,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,OAAO,UAAU,CAAgC;QAC/C,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;KACnC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAA4B,EAC5B,KAAsB;IAEtB,MAAM,CAAC,GAAG,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,OAAO,UAAU,CAAyB;QACxC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;KACnC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,CAAC,GAAG,kBAAkB,EAAE,CAAC;IAC/B,OAAO,UAAU,CAA6B;QAC5C,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;KACnC,CAAoB,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* toolOutcome — the normalized tool-outcome vocabulary, as a PURE leaf
|
|
3
|
+
* (9.34.0).
|
|
4
|
+
*
|
|
5
|
+
* WHY IT LIVES HERE. A skill-graph route edge can key on what a tool
|
|
6
|
+
* DECLARED happened (`onToolStatus`), so this vocabulary is part of the
|
|
7
|
+
* graph's own reading of a turn — `InjectionContext.toolResults[].status`
|
|
8
|
+
* is typed by it. It used to be declared inside `core/agent/toolEffects.ts`,
|
|
9
|
+
* which meant the graph's context type reached into the agent loop's
|
|
10
|
+
* tool-effects module for one string union: the loop's vocabulary embedded
|
|
11
|
+
* in the graph's contract, pointing the dependency the wrong way.
|
|
12
|
+
*
|
|
13
|
+
* So the six words moved DOWN here — a module with zero imports that both
|
|
14
|
+
* sides read. `core/agent/toolEffects.ts` re-exports them under the same
|
|
15
|
+
* names, so every existing import path is unchanged; that module remains
|
|
16
|
+
* the owner of the ENVELOPE grammar (the two effect kinds, the recognizer,
|
|
17
|
+
* the lease shapes), which is genuinely loop-side.
|
|
18
|
+
*
|
|
19
|
+
* Zone: PURE CORE. Pinned by
|
|
20
|
+
* `test/lib/injection-engine/skill-graph-fence.test.ts`.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Normalized outcome of one tool call, declared by the tool itself. Six
|
|
24
|
+
* values, deliberately closed: routing keyed on meaning needs a vocabulary
|
|
25
|
+
* both sides spell identically. A string outside this set makes the value
|
|
26
|
+
* NOT an envelope (data path, unchanged).
|
|
27
|
+
*/
|
|
28
|
+
export type ToolResultStatus = 'success' | 'failure' | 'denied' | 'invalid' | 'partial' | 'pending';
|
|
29
|
+
/** The closed set, as data — validators and docs read one list. */
|
|
30
|
+
export declare const TOOL_RESULT_STATUSES: readonly ToolResultStatus[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* toolOutcome — the normalized tool-outcome vocabulary, as a PURE leaf
|
|
3
|
+
* (9.34.0).
|
|
4
|
+
*
|
|
5
|
+
* WHY IT LIVES HERE. A skill-graph route edge can key on what a tool
|
|
6
|
+
* DECLARED happened (`onToolStatus`), so this vocabulary is part of the
|
|
7
|
+
* graph's own reading of a turn — `InjectionContext.toolResults[].status`
|
|
8
|
+
* is typed by it. It used to be declared inside `core/agent/toolEffects.ts`,
|
|
9
|
+
* which meant the graph's context type reached into the agent loop's
|
|
10
|
+
* tool-effects module for one string union: the loop's vocabulary embedded
|
|
11
|
+
* in the graph's contract, pointing the dependency the wrong way.
|
|
12
|
+
*
|
|
13
|
+
* So the six words moved DOWN here — a module with zero imports that both
|
|
14
|
+
* sides read. `core/agent/toolEffects.ts` re-exports them under the same
|
|
15
|
+
* names, so every existing import path is unchanged; that module remains
|
|
16
|
+
* the owner of the ENVELOPE grammar (the two effect kinds, the recognizer,
|
|
17
|
+
* the lease shapes), which is genuinely loop-side.
|
|
18
|
+
*
|
|
19
|
+
* Zone: PURE CORE. Pinned by
|
|
20
|
+
* `test/lib/injection-engine/skill-graph-fence.test.ts`.
|
|
21
|
+
*/
|
|
22
|
+
/** The closed set, as data — validators and docs read one list. */
|
|
23
|
+
export const TOOL_RESULT_STATUSES = [
|
|
24
|
+
'success',
|
|
25
|
+
'failure',
|
|
26
|
+
'denied',
|
|
27
|
+
'invalid',
|
|
28
|
+
'partial',
|
|
29
|
+
'pending',
|
|
30
|
+
];
|
|
31
|
+
//# sourceMappingURL=toolOutcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolOutcome.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/toolOutcome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAUH,mEAAmE;AACnE,MAAM,CAAC,MAAM,oBAAoB,GAAgC;IAC/D,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC"}
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* iteration. Slot subflows emit `agentfootprint.context.injected`
|
|
17
17
|
* for each InjectionRecord they place.
|
|
18
18
|
*/
|
|
19
|
-
import type { Tool } from '../../core/tools.js';
|
|
20
19
|
import type { ContextRole, ContextSource } from '../../events/types.js';
|
|
20
|
+
import type { SkillCachePolicy, SkillTool, SkillToolSchema } from './hostContract.js';
|
|
21
|
+
import type { ToolResultStatus } from './toolOutcome.js';
|
|
21
22
|
/**
|
|
22
23
|
* Discriminated union — exactly one of four kinds. Adding a new
|
|
23
24
|
* trigger kind is one new variant; engine evaluator + Lens chip
|
|
@@ -89,8 +90,15 @@ export interface InjectionContent {
|
|
|
89
90
|
* and are visible to the model from iteration 1 — activation adds the body,
|
|
90
91
|
* not the tools. Only a Skill with `autoActivate: 'currentSkill'` has its
|
|
91
92
|
* tools held back and readmitted through the tools slot while it is active.
|
|
93
|
+
*
|
|
94
|
+
* Typed as the NARROW {@link SkillTool} — a schema and something to run —
|
|
95
|
+
* rather than agentfootprint's own `Tool` (9.34.0). Every other member of
|
|
96
|
+
* `Tool` is optional, so a `Tool` satisfies this and this is accepted
|
|
97
|
+
* everywhere a `Tool` is; what changes is that DECLARING a skill no longer
|
|
98
|
+
* needs the framework's tool type, which is what lets this engine be read
|
|
99
|
+
* by a host that has its own.
|
|
92
100
|
*/
|
|
93
|
-
readonly tools?: readonly
|
|
101
|
+
readonly tools?: readonly SkillTool[];
|
|
94
102
|
}
|
|
95
103
|
/**
|
|
96
104
|
* Context passed to `rule` predicates. Read-only snapshot of the
|
|
@@ -142,7 +150,7 @@ export interface InjectionContext {
|
|
|
142
150
|
* tool returned a result envelope carrying `status`. `onToolStatus`
|
|
143
151
|
* route edges key on it; a result without one can never match a
|
|
144
152
|
* status edge (an undeclared outcome is not evidence). */
|
|
145
|
-
readonly status?:
|
|
153
|
+
readonly status?: ToolResultStatus;
|
|
146
154
|
}>;
|
|
147
155
|
/**
|
|
148
156
|
* IDs of LLM-activated injections that the LLM has activated this
|
|
@@ -258,7 +266,7 @@ export declare function toolResultsOf(ctx: InjectionContext): ReadonlyArray<{
|
|
|
258
266
|
readonly toolName: string;
|
|
259
267
|
readonly result: string;
|
|
260
268
|
readonly toolCallId?: string;
|
|
261
|
-
readonly status?:
|
|
269
|
+
readonly status?: ToolResultStatus;
|
|
262
270
|
}>;
|
|
263
271
|
/**
|
|
264
272
|
* THE primitive. Five fields. Four trigger kinds. Three slot targets.
|
|
@@ -325,17 +333,33 @@ export interface InjectionEvaluation {
|
|
|
325
333
|
}>;
|
|
326
334
|
}
|
|
327
335
|
/**
|
|
328
|
-
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
336
|
+
* THE BOUNDARY CONTRACT — an active Injection as plain, serializable data.
|
|
337
|
+
*
|
|
338
|
+
* POJO projection of an active Injection: it flows through footprintjs scope
|
|
339
|
+
* (which cannot serialize functions) so that slot subflows can read it across
|
|
340
|
+
* the subflow boundary. It drops the `trigger` (already evaluated) and
|
|
341
|
+
* projects `inject.tools` to SCHEMAS ONLY — the tool's `execute` lives on the
|
|
342
|
+
* host's closure-held registry, looked up by injection id at exec time.
|
|
331
343
|
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
344
|
+
* That description is also, exactly, what a host on ANOTHER framework needs
|
|
345
|
+
* (9.34.0). This is the shape the injection engine hands out: no predicates,
|
|
346
|
+
* no closures, no framework tool objects, nothing that has to survive a
|
|
347
|
+
* `structuredClone` and doesn't. A host reads `inject.systemPrompt` into its
|
|
348
|
+
* own system message, `inject.messages` into its own history, and
|
|
349
|
+
* `inject.tools[].schema` into its own tool list — resolving `execute` by
|
|
350
|
+
* `injectionId` in whatever registry it keeps. Which is why the two fields
|
|
351
|
+
* that used to name our own layers by inline import — the tool schema and the
|
|
352
|
+
* cache directive — are now the structural {@link SkillToolSchema} and
|
|
353
|
+
* {@link SkillCachePolicy} from `hostContract.ts`: the same shapes, spelled
|
|
354
|
+
* without reaching for an adapter or a cache implementation.
|
|
355
|
+
*
|
|
356
|
+
* It is a PROJECTION, not a second source of truth. `projectActiveInjection`
|
|
357
|
+
* below is the only thing that builds one, and a field that is not on its
|
|
358
|
+
* copy list does not cross — see `cache` for what that cost once.
|
|
335
359
|
*/
|
|
336
360
|
export interface ActiveInjection {
|
|
337
361
|
readonly id: string;
|
|
338
|
-
readonly flavor:
|
|
362
|
+
readonly flavor: ContextSource;
|
|
339
363
|
readonly description?: string;
|
|
340
364
|
/**
|
|
341
365
|
* The DECLARED surfaceMode (Skill flavor only), copied through as written.
|
|
@@ -373,7 +397,7 @@ export interface ActiveInjection {
|
|
|
373
397
|
* Absent when the injection declared none (hand-built Injections); the
|
|
374
398
|
* decision's own `?? 'never'` default then applies, as it always did.
|
|
375
399
|
*/
|
|
376
|
-
readonly cache?:
|
|
400
|
+
readonly cache?: SkillCachePolicy;
|
|
377
401
|
/**
|
|
378
402
|
* Why THIS piece of retrieved content earned its place (8.8.0).
|
|
379
403
|
*
|
|
@@ -394,12 +418,12 @@ export interface ActiveInjection {
|
|
|
394
418
|
readonly inject: {
|
|
395
419
|
readonly systemPrompt?: string;
|
|
396
420
|
readonly messages?: ReadonlyArray<{
|
|
397
|
-
readonly role:
|
|
421
|
+
readonly role: ContextRole;
|
|
398
422
|
readonly content: string;
|
|
399
423
|
}>;
|
|
400
424
|
/** Tool schemas only — `execute` lives on Agent's closure registry. */
|
|
401
425
|
readonly tools?: ReadonlyArray<{
|
|
402
|
-
readonly schema:
|
|
426
|
+
readonly schema: SkillToolSchema;
|
|
403
427
|
readonly injectionId: string;
|
|
404
428
|
}>;
|
|
405
429
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAqPH;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAqB;IAMjD,OAAO,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC;AAyKD,wEAAwE;AACxE,MAAM,UAAU,sBAAsB,CAAC,GAAc;IACnD,qEAAqE;IACrE,+DAA+D;IAC/D,0EAA0E;IAC1E,2EAA2E;IAC3E,sBAAsB;IACtB,MAAM,IAAI,GAAG,GAAG,CAAC,QAEJ,CAAC;IACd,MAAM,GAAG,GAAoB;QAC3B,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAA6C,EAAE,CAAC;QAC7F,GAAG,CAAC,IAAI,EAAE,YAAY,IAAI;YACxB,YAAY,EAAE,IAAI,CAAC,YAA+C;SACnE,CAAC;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,yEAAyE;QACzE,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,IAAI;YAC/B,KAAK,EAAE,IAAI,CAAC,KAAiC;SAC9C,CAAC;QACF,MAAM,EAAE;YACN,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpF,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;gBACtB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAClC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;oBACvB,WAAW,EAAE,GAAG,CAAC,EAAE;iBACpB,CAAC,CAAC;aACJ,CAAC;SACH;KACF,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
|