@frankieai/core 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +70 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +69 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ __export(index_exports, {
|
|
|
63
63
|
operationId: () => operationId,
|
|
64
64
|
parseFrankieConfig: () => parseFrankieConfig,
|
|
65
65
|
personaEnvKey: () => personaEnvKey,
|
|
66
|
+
personaInstructions: () => personaInstructions,
|
|
66
67
|
personaProfileSchema: () => personaProfileSchema,
|
|
67
68
|
plainText: () => plainText,
|
|
68
69
|
planHostedInstall: () => planHostedInstall,
|
|
@@ -612,6 +613,18 @@ var personaProfileSchema = import_zod2.z.object({
|
|
|
612
613
|
* sign in.
|
|
613
614
|
*/
|
|
614
615
|
allowAnonymous: import_zod2.z.boolean().optional(),
|
|
616
|
+
/**
|
|
617
|
+
* What this agent helps with, in the team's own words ("pricing, plans,
|
|
618
|
+
* getting started"). The one thing a team needs to write; the agent's role,
|
|
619
|
+
* greeting and instructions come from defaults. It is added to the agent's
|
|
620
|
+
* instructions at runtime (see `personaInstructions`).
|
|
621
|
+
*/
|
|
622
|
+
scope: import_zod2.z.string().trim().max(2e3).optional(),
|
|
623
|
+
/**
|
|
624
|
+
* Where to send people when the agent can't answer and it doesn't hand the
|
|
625
|
+
* chat to the team itself: a contact page (https) or an email (mailto:).
|
|
626
|
+
*/
|
|
627
|
+
contactUrl: import_zod2.z.string().trim().max(500).regex(/^(?:https:\/\/[^\s]+|mailto:[^\s@]+@[^\s@]+)$/, "Use an https:// link or a mailto: address.").optional(),
|
|
615
628
|
/**
|
|
616
629
|
* Shallow-merged over the workspace branding. Each field is optional with no
|
|
617
630
|
* default, so only the keys the persona sets override the workspace's — an
|
|
@@ -678,11 +691,20 @@ function resolvePersonaConfig(config, publishableKey) {
|
|
|
678
691
|
branding: { ...config.branding, ...persona.branding ?? {} },
|
|
679
692
|
auth: { ...config.auth, publishableKey: persona.publishableKey, allowAnonymous: persona.allowAnonymous ?? config.auth.allowAnonymous },
|
|
680
693
|
pagePatterns: persona.pagePatterns,
|
|
681
|
-
agent: persona.agent,
|
|
694
|
+
agent: { ...persona.agent, systemPrompt: personaInstructions(persona) },
|
|
682
695
|
features: persona.features,
|
|
683
696
|
knowledgeBase: persona.knowledgeBase
|
|
684
697
|
});
|
|
685
698
|
}
|
|
699
|
+
function personaInstructions(persona) {
|
|
700
|
+
const base = persona.agent.systemPrompt.trim();
|
|
701
|
+
const scope = persona.scope?.trim();
|
|
702
|
+
const handsOff = persona.features.escalation.enabled;
|
|
703
|
+
const contact = !handsOff ? persona.contactUrl?.trim() : void 0;
|
|
704
|
+
const fallback = handsOff ? "" : contact ? `When you can't answer from what you know, or someone asks for a person, say so briefly and point them to ${contact} to reach the team. Never guess.` : "When you can't answer from what you know, say so plainly. Never guess, and never promise that someone will follow up.";
|
|
705
|
+
const boundary = "Stay within this. If someone asks about something outside it, say briefly that it isn't something you can help with here" + (handsOff ? ", and offer to connect them with the team." : contact ? ", and share the contact link." : ".");
|
|
706
|
+
return [base, scope ? "What you help with, in the team's own words:\n" + scope + "\n\n" + boundary : "", fallback].filter(Boolean).join("\n\n");
|
|
707
|
+
}
|
|
686
708
|
function normalizeRoutePath(value) {
|
|
687
709
|
let path = (value || "/").split(/[?#]/)[0].trim();
|
|
688
710
|
if (!path.startsWith("/")) path = "/" + path;
|
|
@@ -1602,6 +1624,7 @@ function oklchToHex(l, c, hDeg) {
|
|
|
1602
1624
|
var NUMBER = String.raw`-?\d*\.?\d+`;
|
|
1603
1625
|
var parts = (body) => body.replace(/\/.*$/, "").split(/[\s,]+/).filter(Boolean);
|
|
1604
1626
|
function normalizeColor(raw) {
|
|
1627
|
+
if (raw.length > 200) return void 0;
|
|
1605
1628
|
const value = raw.trim().replace(/\s*!important$/, "").toLowerCase();
|
|
1606
1629
|
let match = value.match(/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/);
|
|
1607
1630
|
if (match) {
|
|
@@ -1628,20 +1651,58 @@ function normalizeColor(raw) {
|
|
|
1628
1651
|
}
|
|
1629
1652
|
return void 0;
|
|
1630
1653
|
}
|
|
1654
|
+
function cssBlocks(source) {
|
|
1655
|
+
const blocks = [];
|
|
1656
|
+
let segmentStart = 0;
|
|
1657
|
+
for (let at = 0; at < source.length; ) {
|
|
1658
|
+
const open = source.indexOf("{", at);
|
|
1659
|
+
if (open === -1) break;
|
|
1660
|
+
const nextOpen = source.indexOf("{", open + 1);
|
|
1661
|
+
const close = source.indexOf("}", open + 1);
|
|
1662
|
+
if (close === -1) break;
|
|
1663
|
+
if (nextOpen !== -1 && nextOpen < close) {
|
|
1664
|
+
segmentStart = open + 1;
|
|
1665
|
+
at = open + 1;
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
blocks.push([source.slice(segmentStart, open), source.slice(open + 1, close)]);
|
|
1669
|
+
segmentStart = close + 1;
|
|
1670
|
+
at = close + 1;
|
|
1671
|
+
}
|
|
1672
|
+
return blocks;
|
|
1673
|
+
}
|
|
1674
|
+
function customProperty(declaration) {
|
|
1675
|
+
const colon = declaration.indexOf(":");
|
|
1676
|
+
if (colon === -1) return void 0;
|
|
1677
|
+
const name = declaration.slice(0, colon).trim();
|
|
1678
|
+
const value = declaration.slice(colon + 1).trim();
|
|
1679
|
+
return name.length <= 100 && value.length <= 200 && /^--[\w-]+$/.test(name) && value ? [name, value] : void 0;
|
|
1680
|
+
}
|
|
1631
1681
|
function rootVariables(css) {
|
|
1632
1682
|
const vars = /* @__PURE__ */ new Map();
|
|
1633
|
-
const source = css
|
|
1634
|
-
const
|
|
1635
|
-
|
|
1636
|
-
|
|
1683
|
+
const source = stripComments(css);
|
|
1684
|
+
for (const [rawSelector, body] of cssBlocks(source)) {
|
|
1685
|
+
const selector = rawSelector.split(";").pop().trim();
|
|
1686
|
+
if (selector.length > 1e3) continue;
|
|
1637
1687
|
if (!/(?:^|[\s,]):root\b(?![^,]*\.dark)|^@theme\b/.test(selector) || /\.dark|\[data-theme/.test(selector)) continue;
|
|
1638
|
-
for (const declaration of
|
|
1639
|
-
const found = declaration
|
|
1640
|
-
if (found && !vars.has(found[
|
|
1688
|
+
for (const declaration of body.split(";")) {
|
|
1689
|
+
const found = customProperty(declaration);
|
|
1690
|
+
if (found && !vars.has(found[0])) vars.set(found[0], found[1]);
|
|
1641
1691
|
}
|
|
1642
1692
|
}
|
|
1643
1693
|
return vars;
|
|
1644
1694
|
}
|
|
1695
|
+
function stripComments(css) {
|
|
1696
|
+
let out = "";
|
|
1697
|
+
for (let at = 0; ; ) {
|
|
1698
|
+
const start = css.indexOf("/*", at);
|
|
1699
|
+
if (start === -1) return out + css.slice(at);
|
|
1700
|
+
out += css.slice(at, start);
|
|
1701
|
+
const end = css.indexOf("*/", start + 2);
|
|
1702
|
+
if (end === -1) return out;
|
|
1703
|
+
at = end + 2;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1645
1706
|
function resolve(value, vars, depth = 0) {
|
|
1646
1707
|
if (depth > 4) return void 0;
|
|
1647
1708
|
const reference = value.match(/^(?:(hsla?|oklch|rgba?)\(\s*)?var\(\s*(--[\w-]+)\s*(?:,[^)]*)?\)\s*\)?$/i);
|
|
@@ -1754,6 +1815,7 @@ function inferTheme(files, root = "") {
|
|
|
1754
1815
|
operationId,
|
|
1755
1816
|
parseFrankieConfig,
|
|
1756
1817
|
personaEnvKey,
|
|
1818
|
+
personaInstructions,
|
|
1757
1819
|
personaProfileSchema,
|
|
1758
1820
|
plainText,
|
|
1759
1821
|
planHostedInstall,
|