@avocadostudio-ai/orchestrator-core 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 +201 -0
- package/dist/agent/agent-context.d.ts +19 -0
- package/dist/agent/agent-context.js +67 -0
- package/dist/agent/agent-logger.d.ts +5 -0
- package/dist/agent/agent-logger.js +22 -0
- package/dist/agent/agent-loop-openai.d.ts +8 -0
- package/dist/agent/agent-loop-openai.js +172 -0
- package/dist/agent/agent-loop.d.ts +56 -0
- package/dist/agent/agent-loop.js +167 -0
- package/dist/agent/agent-provider.d.ts +28 -0
- package/dist/agent/agent-provider.js +63 -0
- package/dist/agent/agent-tools.d.ts +28 -0
- package/dist/agent/agent-tools.js +899 -0
- package/dist/agent/context/editing-guidelines.md +46 -0
- package/dist/agent/context/role.md +39 -0
- package/dist/agent/integration-prompt.d.ts +9 -0
- package/dist/agent/integration-prompt.js +154 -0
- package/dist/agent/sites-agent-context.d.ts +12 -0
- package/dist/agent/sites-agent-context.js +316 -0
- package/dist/agent/sites-agent-shared.d.ts +161 -0
- package/dist/agent/sites-agent-shared.js +1101 -0
- package/dist/agent/sites-agent-tools.d.ts +18 -0
- package/dist/agent/sites-agent-tools.js +1227 -0
- package/dist/chat/anthropic-cache.d.ts +20 -0
- package/dist/chat/anthropic-cache.js +54 -0
- package/dist/chat/anthropic-planner.d.ts +98 -0
- package/dist/chat/anthropic-planner.js +1012 -0
- package/dist/chat/changelog-coverage-validator.d.ts +37 -0
- package/dist/chat/changelog-coverage-validator.js +215 -0
- package/dist/chat/chat-pipeline-context.d.ts +211 -0
- package/dist/chat/chat-pipeline-context.js +249 -0
- package/dist/chat/chat-pipeline-deterministic.d.ts +61 -0
- package/dist/chat/chat-pipeline-deterministic.js +407 -0
- package/dist/chat/chat-pipeline-image.d.ts +86 -0
- package/dist/chat/chat-pipeline-image.js +897 -0
- package/dist/chat/chat-pipeline-shared.d.ts +69 -0
- package/dist/chat/chat-pipeline-shared.js +212 -0
- package/dist/chat/chat-pipeline-translation.d.ts +27 -0
- package/dist/chat/chat-pipeline-translation.js +417 -0
- package/dist/chat/chat-pipeline-ui.d.ts +14 -0
- package/dist/chat/chat-pipeline-ui.js +244 -0
- package/dist/chat/chat-pipeline.d.ts +99 -0
- package/dist/chat/chat-pipeline.js +3999 -0
- package/dist/chat/decomposer.d.ts +21 -0
- package/dist/chat/decomposer.js +65 -0
- package/dist/chat/gemini-planner.d.ts +70 -0
- package/dist/chat/gemini-planner.js +541 -0
- package/dist/chat/hallucination-validator.d.ts +36 -0
- package/dist/chat/hallucination-validator.js +110 -0
- package/dist/chat/locale-strings.d.ts +47 -0
- package/dist/chat/locale-strings.js +100 -0
- package/dist/chat/plan-json-schema.d.ts +133 -0
- package/dist/chat/plan-json-schema.js +112 -0
- package/dist/chat/planner-types.d.ts +120 -0
- package/dist/chat/planner-types.js +66 -0
- package/dist/chat/planner.d.ts +148 -0
- package/dist/chat/planner.js +1361 -0
- package/dist/chat/prompts.d.ts +67 -0
- package/dist/chat/prompts.js +356 -0
- package/dist/chat/provider-routing.d.ts +14 -0
- package/dist/chat/provider-routing.js +27 -0
- package/dist/chat/variation-pipeline.d.ts +135 -0
- package/dist/chat/variation-pipeline.js +837 -0
- package/dist/chat/vision-alt-generator.d.ts +35 -0
- package/dist/chat/vision-alt-generator.js +152 -0
- package/dist/cms/adapter.d.ts +62 -0
- package/dist/cms/adapter.js +1 -0
- package/dist/cms/bootstrap.d.ts +17 -0
- package/dist/cms/bootstrap.js +85 -0
- package/dist/cms/editor-api-adapter.d.ts +23 -0
- package/dist/cms/editor-api-adapter.js +71 -0
- package/dist/cms/index.d.ts +4 -0
- package/dist/cms/index.js +3 -0
- package/dist/cms/json-file-adapter.d.ts +11 -0
- package/dist/cms/json-file-adapter.js +62 -0
- package/dist/demo-mode.d.ts +59 -0
- package/dist/demo-mode.js +201 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.js +129 -0
- package/dist/http/chat-stream-resumable.d.ts +108 -0
- package/dist/http/chat-stream-resumable.js +290 -0
- package/dist/http/chat-stream.d.ts +99 -0
- package/dist/http/chat-stream.js +92 -0
- package/dist/image/gdrive-client.d.ts +22 -0
- package/dist/image/gdrive-client.js +215 -0
- package/dist/image/image-helpers.d.ts +95 -0
- package/dist/image/image-helpers.js +488 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/jira/jira-approval.d.ts +22 -0
- package/dist/jira/jira-approval.js +51 -0
- package/dist/jira/jira-client.d.ts +44 -0
- package/dist/jira/jira-client.js +313 -0
- package/dist/jira/jira-poller.d.ts +46 -0
- package/dist/jira/jira-poller.js +184 -0
- package/dist/jira/jira-processor.d.ts +103 -0
- package/dist/jira/jira-processor.js +1085 -0
- package/dist/jira/jira-types.d.ts +117 -0
- package/dist/jira/jira-types.js +38 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +28 -0
- package/dist/migration/mcp-server-stdio.d.ts +8 -0
- package/dist/migration/mcp-server-stdio.js +672 -0
- package/dist/migration/migration-prompt.d.ts +7 -0
- package/dist/migration/migration-prompt.js +197 -0
- package/dist/migration/migration-tools.d.ts +17 -0
- package/dist/migration/migration-tools.js +159 -0
- package/dist/migration/scrape-cache.d.ts +9 -0
- package/dist/migration/scrape-cache.js +19 -0
- package/dist/nlp/deterministic-planner-context.d.ts +141 -0
- package/dist/nlp/deterministic-planner-context.js +362 -0
- package/dist/nlp/deterministic-planner-pages.d.ts +26 -0
- package/dist/nlp/deterministic-planner-pages.js +170 -0
- package/dist/nlp/deterministic-planner-patches.d.ts +80 -0
- package/dist/nlp/deterministic-planner-patches.js +508 -0
- package/dist/nlp/deterministic-planner-refs.d.ts +33 -0
- package/dist/nlp/deterministic-planner-refs.js +164 -0
- package/dist/nlp/deterministic-planner-suggestions.d.ts +49 -0
- package/dist/nlp/deterministic-planner-suggestions.js +579 -0
- package/dist/nlp/deterministic-planner.d.ts +85 -0
- package/dist/nlp/deterministic-planner.js +1631 -0
- package/dist/nlp/intent-detection.d.ts +309 -0
- package/dist/nlp/intent-detection.js +730 -0
- package/dist/nlp/intent-helpers.d.ts +15 -0
- package/dist/nlp/intent-helpers.js +243 -0
- package/dist/nlp/intent-patterns.d.ts +40 -0
- package/dist/nlp/intent-patterns.js +223 -0
- package/dist/nlp/plan-normalizer.d.ts +41 -0
- package/dist/nlp/plan-normalizer.js +1537 -0
- package/dist/ops/destructive-action-gate.d.ts +44 -0
- package/dist/ops/destructive-action-gate.js +90 -0
- package/dist/ops/ops-engine.d.ts +151 -0
- package/dist/ops/ops-engine.js +1394 -0
- package/dist/publish/diff-engine.d.ts +18 -0
- package/dist/publish/diff-engine.js +305 -0
- package/dist/publish/publish-helpers.d.ts +87 -0
- package/dist/publish/publish-helpers.js +521 -0
- package/dist/publish/publish-target-registry.d.ts +7 -0
- package/dist/publish/publish-target-registry.js +61 -0
- package/dist/publish/publish-target.d.ts +81 -0
- package/dist/publish/publish-target.js +1 -0
- package/dist/publish/targets/deploy-hook.d.ts +13 -0
- package/dist/publish/targets/deploy-hook.js +123 -0
- package/dist/publish/targets/git.d.ts +13 -0
- package/dist/publish/targets/git.js +55 -0
- package/dist/publish/targets/site-contract.d.ts +19 -0
- package/dist/publish/targets/site-contract.js +124 -0
- package/dist/state/content-source.d.ts +17 -0
- package/dist/state/content-source.js +1 -0
- package/dist/state/in-memory-content-source.d.ts +27 -0
- package/dist/state/in-memory-content-source.js +51 -0
- package/dist/state/session-lock.d.ts +13 -0
- package/dist/state/session-lock.js +29 -0
- package/dist/state/session-state.d.ts +310 -0
- package/dist/state/session-state.js +1083 -0
- package/dist/state/sqlite-store-singleton.d.ts +31 -0
- package/dist/state/sqlite-store-singleton.js +170 -0
- package/dist/state/sqlite-store.d.ts +135 -0
- package/dist/state/sqlite-store.js +421 -0
- package/dist/telemetry/chat-telemetry.d.ts +105 -0
- package/dist/telemetry/chat-telemetry.js +247 -0
- package/dist/telemetry/eval-candidate-store.d.ts +50 -0
- package/dist/telemetry/eval-candidate-store.js +120 -0
- package/dist/telemetry/feedback-store.d.ts +34 -0
- package/dist/telemetry/feedback-store.js +76 -0
- package/dist/telemetry/jira-telemetry.d.ts +57 -0
- package/dist/telemetry/jira-telemetry.js +68 -0
- package/dist/telemetry/migration-telemetry.d.ts +35 -0
- package/dist/telemetry/migration-telemetry.js +40 -0
- package/dist/telemetry/usage.d.ts +24 -0
- package/dist/telemetry/usage.js +80 -0
- package/dist/tools/builtin-registrations.d.ts +12 -0
- package/dist/tools/builtin-registrations.js +33 -0
- package/dist/tools/builtins/gdrive-browse.d.ts +3 -0
- package/dist/tools/builtins/gdrive-browse.js +68 -0
- package/dist/tools/builtins/image-generate.d.ts +3 -0
- package/dist/tools/builtins/image-generate.js +211 -0
- package/dist/tools/builtins/unsplash-get-by-id.d.ts +23 -0
- package/dist/tools/builtins/unsplash-get-by-id.js +119 -0
- package/dist/tools/builtins/unsplash-search.d.ts +3 -0
- package/dist/tools/builtins/unsplash-search.js +74 -0
- package/dist/tools/executor.d.ts +23 -0
- package/dist/tools/executor.js +169 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/registry.d.ts +21 -0
- package/dist/tools/registry.js +75 -0
- package/dist/tools/runtime.d.ts +27 -0
- package/dist/tools/runtime.js +48 -0
- package/dist/tools/schema-validator.d.ts +24 -0
- package/dist/tools/schema-validator.js +88 -0
- package/dist/tools/types.d.ts +86 -0
- package/dist/tools/types.js +1 -0
- package/dist/variation-images.d.ts +19 -0
- package/dist/variation-images.js +12 -0
- package/package.json +78 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side locale strings for deterministic planner responses.
|
|
3
|
+
* Covers summary_for_user messages that bypass the LLM.
|
|
4
|
+
*/
|
|
5
|
+
export type ServerLocale = "en" | "de";
|
|
6
|
+
declare const en: {
|
|
7
|
+
readonly "rename.needsPath": "Please provide the target page path, for example: rename page from /old to /new.";
|
|
8
|
+
readonly "rename.done": "Renamed page path from {{from}} to {{to}}.";
|
|
9
|
+
readonly "delete.homeBlocked": "The home page cannot be deleted. Navigate to a different page first, or specify which page to delete (e.g. \"delete /about\").";
|
|
10
|
+
readonly "delete.done": "Deleted page {{slug}}.";
|
|
11
|
+
readonly "move.notFound": "I could not find page {{slug}}.";
|
|
12
|
+
readonly "move.homeFixed": "Home page (/) is fixed at the first position in navigation.";
|
|
13
|
+
readonly "move.specifyWhere": "Specify where to place the page (first/last/before/after).";
|
|
14
|
+
readonly "move.anchorNotFound": "I could not find anchor page {{slug}}.";
|
|
15
|
+
readonly "move.done": "Moved **{{slug}}** {{direction}}.";
|
|
16
|
+
readonly "audience.done": "Tailored this page for {{audience}}.";
|
|
17
|
+
readonly "reorder.specify": "I can reorder sections if needed, but please specify what should move (for example: move FAQ below Testimonials).";
|
|
18
|
+
readonly "hero.secondaryCta": "Added a secondary CTA button to the selected Hero.";
|
|
19
|
+
readonly "update.done": "Updated {{type}}.";
|
|
20
|
+
readonly "update.specify": "Please specify the section and exact change you want.";
|
|
21
|
+
readonly "update.needsBlock": "I need to know which block to update.";
|
|
22
|
+
readonly "update.invalidFields": "Please specify at least one valid field for {{type}}.";
|
|
23
|
+
readonly "remove.allAlready": "All blocks are already {{type}} — nothing to remove.";
|
|
24
|
+
readonly "remove.keptOnly": "Removed all blocks except {{type}}.";
|
|
25
|
+
readonly "remove.needsBlock": "I need to know which block to remove.";
|
|
26
|
+
readonly "remove.specifyItem": "Please specify which item to remove (e.g., \"the first question\", \"the last item\").";
|
|
27
|
+
readonly "remove.outOfRange": "There are only {{count}} items in {{type}} — cannot remove item {{index}}.";
|
|
28
|
+
readonly "remove.itemDone": "Removed an item from {{type}}.";
|
|
29
|
+
readonly "remove.done": "Removed {{type}}.";
|
|
30
|
+
readonly "move.needsBlock": "I need to know which block to move.";
|
|
31
|
+
readonly "move.anchorBlockNotFound": "I could not find the anchor block to move after.";
|
|
32
|
+
readonly "move.anchorBlockBeforeNotFound": "I could not find the anchor block to move before.";
|
|
33
|
+
readonly "move.specifyDirection": "Please specify where to move the block (top, bottom, before, after).";
|
|
34
|
+
readonly "move.blockDone": "Moved {{type}}.";
|
|
35
|
+
readonly "add.multiple": "Added {{types}}.";
|
|
36
|
+
readonly "add.heroImage": "Updated the hero image.";
|
|
37
|
+
readonly "add.specifyType": "Please specify which block type to add ({{types}}).";
|
|
38
|
+
readonly "add.itemDone": "Added an item to {{type}}.";
|
|
39
|
+
readonly "add.anchorAfterNotFound": "I could not find the anchor block to place this after.";
|
|
40
|
+
readonly "add.anchorBeforeNotFound": "I could not find the anchor block to place this before.";
|
|
41
|
+
readonly "add.done": "Added {{type}}.";
|
|
42
|
+
readonly "duplicate.done": "Duplicated {{type}}.";
|
|
43
|
+
readonly "duplicate.pageDone": "Duplicated page {{from}} as {{to}}.";
|
|
44
|
+
};
|
|
45
|
+
type ServerStringKey = keyof typeof en;
|
|
46
|
+
export declare function st(locale: string | undefined, key: ServerStringKey, vars?: Record<string, string | number>): string;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side locale strings for deterministic planner responses.
|
|
3
|
+
* Covers summary_for_user messages that bypass the LLM.
|
|
4
|
+
*/
|
|
5
|
+
function resolveLocale(locale) {
|
|
6
|
+
if (locale === "de")
|
|
7
|
+
return "de";
|
|
8
|
+
return "en";
|
|
9
|
+
}
|
|
10
|
+
const en = {
|
|
11
|
+
"rename.needsPath": "Please provide the target page path, for example: rename page from /old to /new.",
|
|
12
|
+
"rename.done": "Renamed page path from {{from}} to {{to}}.",
|
|
13
|
+
"delete.homeBlocked": "The home page cannot be deleted. Navigate to a different page first, or specify which page to delete (e.g. \"delete /about\").",
|
|
14
|
+
"delete.done": "Deleted page {{slug}}.",
|
|
15
|
+
"move.notFound": "I could not find page {{slug}}.",
|
|
16
|
+
"move.homeFixed": "Home page (/) is fixed at the first position in navigation.",
|
|
17
|
+
"move.specifyWhere": "Specify where to place the page (first/last/before/after).",
|
|
18
|
+
"move.anchorNotFound": "I could not find anchor page {{slug}}.",
|
|
19
|
+
"move.done": "Moved **{{slug}}** {{direction}}.",
|
|
20
|
+
"audience.done": "Tailored this page for {{audience}}.",
|
|
21
|
+
"reorder.specify": "I can reorder sections if needed, but please specify what should move (for example: move FAQ below Testimonials).",
|
|
22
|
+
"hero.secondaryCta": "Added a secondary CTA button to the selected Hero.",
|
|
23
|
+
"update.done": "Updated {{type}}.",
|
|
24
|
+
"update.specify": "Please specify the section and exact change you want.",
|
|
25
|
+
"update.needsBlock": "I need to know which block to update.",
|
|
26
|
+
"update.invalidFields": "Please specify at least one valid field for {{type}}.",
|
|
27
|
+
"remove.allAlready": "All blocks are already {{type}} — nothing to remove.",
|
|
28
|
+
"remove.keptOnly": "Removed all blocks except {{type}}.",
|
|
29
|
+
"remove.needsBlock": "I need to know which block to remove.",
|
|
30
|
+
"remove.specifyItem": "Please specify which item to remove (e.g., \"the first question\", \"the last item\").",
|
|
31
|
+
"remove.outOfRange": "There are only {{count}} items in {{type}} — cannot remove item {{index}}.",
|
|
32
|
+
"remove.itemDone": "Removed an item from {{type}}.",
|
|
33
|
+
"remove.done": "Removed {{type}}.",
|
|
34
|
+
"move.needsBlock": "I need to know which block to move.",
|
|
35
|
+
"move.anchorBlockNotFound": "I could not find the anchor block to move after.",
|
|
36
|
+
"move.anchorBlockBeforeNotFound": "I could not find the anchor block to move before.",
|
|
37
|
+
"move.specifyDirection": "Please specify where to move the block (top, bottom, before, after).",
|
|
38
|
+
"move.blockDone": "Moved {{type}}.",
|
|
39
|
+
"add.multiple": "Added {{types}}.",
|
|
40
|
+
"add.heroImage": "Updated the hero image.",
|
|
41
|
+
"add.specifyType": "Please specify which block type to add ({{types}}).",
|
|
42
|
+
"add.itemDone": "Added an item to {{type}}.",
|
|
43
|
+
"add.anchorAfterNotFound": "I could not find the anchor block to place this after.",
|
|
44
|
+
"add.anchorBeforeNotFound": "I could not find the anchor block to place this before.",
|
|
45
|
+
"add.done": "Added {{type}}.",
|
|
46
|
+
"duplicate.done": "Duplicated {{type}}.",
|
|
47
|
+
"duplicate.pageDone": "Duplicated page {{from}} as {{to}}.",
|
|
48
|
+
};
|
|
49
|
+
const strings = {
|
|
50
|
+
en,
|
|
51
|
+
de: {
|
|
52
|
+
"rename.needsPath": "Bitte gib den Zielpfad an, zum Beispiel: Seite umbenennen von /alt nach /neu.",
|
|
53
|
+
"rename.done": "Seitenpfad von {{from}} nach {{to}} umbenannt.",
|
|
54
|
+
"delete.homeBlocked": "Die Startseite kann nicht gel\u00F6scht werden. Navigiere zuerst zu einer anderen Seite oder gib an, welche Seite gel\u00F6scht werden soll (z.\u00A0B. \"/about l\u00F6schen\").",
|
|
55
|
+
"delete.done": "Seite {{slug}} gelöscht.",
|
|
56
|
+
"move.notFound": "Seite {{slug}} nicht gefunden.",
|
|
57
|
+
"move.homeFixed": "Die Startseite (/) ist fest an erster Stelle in der Navigation.",
|
|
58
|
+
"move.specifyWhere": "Gib an, wohin die Seite verschoben werden soll (erste/letzte/vor/nach).",
|
|
59
|
+
"move.anchorNotFound": "Ankerseite {{slug}} nicht gefunden.",
|
|
60
|
+
"move.done": "**{{slug}}** {{direction}} verschoben.",
|
|
61
|
+
"audience.done": "Diese Seite wurde für {{audience}} angepasst.",
|
|
62
|
+
"reorder.specify": "Ich kann Bereiche umordnen, aber bitte gib an, was verschoben werden soll (z.\u00A0B.: FAQ unter Testimonials verschieben).",
|
|
63
|
+
"hero.secondaryCta": "Sekundären CTA-Button zum ausgewählten Hero hinzugefügt.",
|
|
64
|
+
"update.done": "{{type}} aktualisiert.",
|
|
65
|
+
"update.specify": "Bitte gib den Bereich und die gewünschte Änderung an.",
|
|
66
|
+
"update.needsBlock": "Ich muss wissen, welcher Block aktualisiert werden soll.",
|
|
67
|
+
"update.invalidFields": "Bitte gib mindestens ein gültiges Feld für {{type}} an.",
|
|
68
|
+
"remove.allAlready": "Alle Blöcke sind bereits {{type}} — nichts zu entfernen.",
|
|
69
|
+
"remove.keptOnly": "Alle Blöcke außer {{type}} entfernt.",
|
|
70
|
+
"remove.needsBlock": "Ich muss wissen, welcher Block entfernt werden soll.",
|
|
71
|
+
"remove.specifyItem": "Bitte gib an, welches Element entfernt werden soll (z.\u00A0B. 'die erste Frage', 'das letzte Element').",
|
|
72
|
+
"remove.outOfRange": "Es gibt nur {{count}} Elemente in {{type}} — Element {{index}} kann nicht entfernt werden.",
|
|
73
|
+
"remove.itemDone": "Element aus {{type}} entfernt.",
|
|
74
|
+
"remove.done": "{{type}} entfernt.",
|
|
75
|
+
"move.needsBlock": "Ich muss wissen, welcher Block verschoben werden soll.",
|
|
76
|
+
"move.anchorBlockNotFound": "Ankerblock zum Verschieben nicht gefunden.",
|
|
77
|
+
"move.anchorBlockBeforeNotFound": "Ankerblock zum Davor-Platzieren nicht gefunden.",
|
|
78
|
+
"move.specifyDirection": "Bitte gib an, wohin der Block verschoben werden soll (oben, unten, vor, nach).",
|
|
79
|
+
"move.blockDone": "{{type}} verschoben.",
|
|
80
|
+
"add.multiple": "{{types}} hinzugefügt.",
|
|
81
|
+
"add.heroImage": "Hero-Bild aktualisiert.",
|
|
82
|
+
"add.specifyType": "Bitte gib den Blocktyp an, der hinzugefügt werden soll ({{types}}).",
|
|
83
|
+
"add.itemDone": "Element zu {{type}} hinzugefügt.",
|
|
84
|
+
"add.anchorAfterNotFound": "Ankerblock zum Danach-Platzieren nicht gefunden.",
|
|
85
|
+
"add.anchorBeforeNotFound": "Ankerblock zum Davor-Platzieren nicht gefunden.",
|
|
86
|
+
"add.done": "{{type}} hinzugefügt.",
|
|
87
|
+
"duplicate.done": "{{type}} dupliziert.",
|
|
88
|
+
"duplicate.pageDone": "Seite {{from}} als {{to}} dupliziert.",
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
export function st(locale, key, vars) {
|
|
92
|
+
const l = resolveLocale(locale);
|
|
93
|
+
let str = strings[l][key] ?? strings.en[key] ?? key;
|
|
94
|
+
if (vars) {
|
|
95
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
96
|
+
str = str.replaceAll(`{{${k}}}`, String(v));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return str;
|
|
100
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export declare const editPlanJsonSchema: {
|
|
2
|
+
readonly type: "object";
|
|
3
|
+
readonly additionalProperties: false;
|
|
4
|
+
readonly properties: {
|
|
5
|
+
readonly intent: {
|
|
6
|
+
readonly type: "string";
|
|
7
|
+
readonly enum: readonly ["edit_plan", "needs_clarification", "content_answer"];
|
|
8
|
+
readonly description: "Whether this is a concrete edit plan, a clarification request, or a read-only answer about page content.";
|
|
9
|
+
};
|
|
10
|
+
readonly summary_for_user: {
|
|
11
|
+
readonly type: "string";
|
|
12
|
+
readonly description: "Human-readable summary of what was done. Use past tense. Use **bold** and bullet lists (- item) for readability when listing multiple points.";
|
|
13
|
+
};
|
|
14
|
+
readonly change_log: {
|
|
15
|
+
readonly type: "string";
|
|
16
|
+
readonly description: "Markdown summary of changes, one line per operation.";
|
|
17
|
+
};
|
|
18
|
+
readonly ops: {
|
|
19
|
+
readonly type: "array";
|
|
20
|
+
readonly items: {
|
|
21
|
+
readonly type: "object";
|
|
22
|
+
readonly additionalProperties: false;
|
|
23
|
+
readonly properties: {
|
|
24
|
+
readonly op: {
|
|
25
|
+
readonly type: "string";
|
|
26
|
+
readonly description: "Operation name";
|
|
27
|
+
};
|
|
28
|
+
readonly pageSlug: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
};
|
|
31
|
+
readonly blockId: {
|
|
32
|
+
readonly type: "string";
|
|
33
|
+
};
|
|
34
|
+
readonly afterBlockId: {
|
|
35
|
+
readonly type: "string";
|
|
36
|
+
};
|
|
37
|
+
readonly newBlockId: {
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
};
|
|
40
|
+
readonly toPageSlug: {
|
|
41
|
+
readonly type: "string";
|
|
42
|
+
};
|
|
43
|
+
readonly newPageSlug: {
|
|
44
|
+
readonly type: "string";
|
|
45
|
+
};
|
|
46
|
+
readonly newTitle: {
|
|
47
|
+
readonly type: "string";
|
|
48
|
+
};
|
|
49
|
+
readonly afterPageSlug: {
|
|
50
|
+
readonly type: "string";
|
|
51
|
+
};
|
|
52
|
+
readonly listKey: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
};
|
|
55
|
+
readonly index: {
|
|
56
|
+
readonly type: "integer";
|
|
57
|
+
};
|
|
58
|
+
readonly afterIndex: {
|
|
59
|
+
readonly type: "integer";
|
|
60
|
+
};
|
|
61
|
+
readonly patch: {
|
|
62
|
+
readonly type: "object";
|
|
63
|
+
};
|
|
64
|
+
readonly block: {
|
|
65
|
+
readonly type: "object";
|
|
66
|
+
};
|
|
67
|
+
readonly page: {
|
|
68
|
+
readonly type: "object";
|
|
69
|
+
};
|
|
70
|
+
readonly item: {
|
|
71
|
+
readonly type: "object";
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
readonly required: readonly ["op"];
|
|
75
|
+
};
|
|
76
|
+
readonly description: "Array of operations. Each has 'op' plus operation-specific fields.";
|
|
77
|
+
};
|
|
78
|
+
readonly suggested_next_actions: {
|
|
79
|
+
readonly type: "array";
|
|
80
|
+
readonly items: {
|
|
81
|
+
readonly type: "string";
|
|
82
|
+
};
|
|
83
|
+
readonly description: "2-4 short imperative phrases the user could type next.";
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
readonly required: string[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Returns the EditPlan schema for a request. In plan-first review mode the
|
|
90
|
+
* `intent` enum is narrowed to `["edit_plan"]` so the model CANNOT emit
|
|
91
|
+
* needs_clarification / content_answer — it must produce a concrete, reviewable
|
|
92
|
+
* plan (the Apply/Discard preview gate makes a wrong guess one-click-discardable,
|
|
93
|
+
* so bailing to a question is never the right move). Prompt directives alone
|
|
94
|
+
* proved unreliable here; constraining the output schema is the hard guarantee.
|
|
95
|
+
*/
|
|
96
|
+
export declare function buildEditPlanJsonSchema(opts?: {
|
|
97
|
+
planFirstMode?: boolean;
|
|
98
|
+
}): typeof editPlanJsonSchema;
|
|
99
|
+
export declare const intentJsonSchema: {
|
|
100
|
+
type: "object";
|
|
101
|
+
additionalProperties: boolean;
|
|
102
|
+
properties: {
|
|
103
|
+
action: {
|
|
104
|
+
type: "string";
|
|
105
|
+
enum: string[];
|
|
106
|
+
};
|
|
107
|
+
target_block_ref: {
|
|
108
|
+
anyOf: Record<string, unknown>[];
|
|
109
|
+
};
|
|
110
|
+
target_block_type: {
|
|
111
|
+
anyOf: Record<string, unknown>[];
|
|
112
|
+
};
|
|
113
|
+
new_block_type: {
|
|
114
|
+
anyOf: Record<string, unknown>[];
|
|
115
|
+
};
|
|
116
|
+
position: {
|
|
117
|
+
anyOf: Record<string, unknown>[];
|
|
118
|
+
};
|
|
119
|
+
anchor_block_ref: {
|
|
120
|
+
anyOf: Record<string, unknown>[];
|
|
121
|
+
};
|
|
122
|
+
summary: {
|
|
123
|
+
anyOf: Record<string, unknown>[];
|
|
124
|
+
};
|
|
125
|
+
assumption: {
|
|
126
|
+
anyOf: Record<string, unknown>[];
|
|
127
|
+
};
|
|
128
|
+
complexity: {
|
|
129
|
+
anyOf: Record<string, unknown>[];
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
required: string[];
|
|
133
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { allowedBlockTypes } from "@avocadostudio-ai/shared";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// JSON Schema for EditPlan — used as Anthropic tool_use input_schema and
|
|
4
|
+
// OpenAI json_schema response_format.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Intentionally loose on the ops array: the downstream normalizePlanCandidate +
|
|
7
|
+
// Zod editPlanSchema validation handles strict validation and repair. Keeping
|
|
8
|
+
// the schema simple avoids the model fighting overly-rigid constraints while
|
|
9
|
+
// still guaranteeing we get structured JSON instead of prose.
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export const editPlanJsonSchema = {
|
|
12
|
+
type: "object",
|
|
13
|
+
additionalProperties: false,
|
|
14
|
+
properties: {
|
|
15
|
+
intent: {
|
|
16
|
+
type: "string",
|
|
17
|
+
enum: ["edit_plan", "needs_clarification", "content_answer"],
|
|
18
|
+
description: "Whether this is a concrete edit plan, a clarification request, or a read-only answer about page content."
|
|
19
|
+
},
|
|
20
|
+
summary_for_user: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Human-readable summary of what was done. Use past tense. Use **bold** and bullet lists (- item) for readability when listing multiple points."
|
|
23
|
+
},
|
|
24
|
+
change_log: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Markdown summary of changes, one line per operation."
|
|
27
|
+
},
|
|
28
|
+
ops: {
|
|
29
|
+
type: "array",
|
|
30
|
+
items: {
|
|
31
|
+
type: "object",
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
properties: {
|
|
34
|
+
op: { type: "string", description: "Operation name" },
|
|
35
|
+
pageSlug: { type: "string" },
|
|
36
|
+
blockId: { type: "string" },
|
|
37
|
+
afterBlockId: { type: "string" },
|
|
38
|
+
newBlockId: { type: "string" },
|
|
39
|
+
toPageSlug: { type: "string" },
|
|
40
|
+
newPageSlug: { type: "string" },
|
|
41
|
+
newTitle: { type: "string" },
|
|
42
|
+
afterPageSlug: { type: "string" },
|
|
43
|
+
listKey: { type: "string" },
|
|
44
|
+
index: { type: "integer" },
|
|
45
|
+
afterIndex: { type: "integer" },
|
|
46
|
+
patch: { type: "object" },
|
|
47
|
+
block: { type: "object" },
|
|
48
|
+
page: { type: "object" },
|
|
49
|
+
item: { type: "object" }
|
|
50
|
+
},
|
|
51
|
+
required: ["op"]
|
|
52
|
+
},
|
|
53
|
+
description: "Array of operations. Each has 'op' plus operation-specific fields."
|
|
54
|
+
},
|
|
55
|
+
suggested_next_actions: {
|
|
56
|
+
type: "array",
|
|
57
|
+
items: { type: "string" },
|
|
58
|
+
description: "2-4 short imperative phrases the user could type next."
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
required: ["intent", "summary_for_user", "change_log", "ops"]
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Returns the EditPlan schema for a request. In plan-first review mode the
|
|
65
|
+
* `intent` enum is narrowed to `["edit_plan"]` so the model CANNOT emit
|
|
66
|
+
* needs_clarification / content_answer — it must produce a concrete, reviewable
|
|
67
|
+
* plan (the Apply/Discard preview gate makes a wrong guess one-click-discardable,
|
|
68
|
+
* so bailing to a question is never the right move). Prompt directives alone
|
|
69
|
+
* proved unreliable here; constraining the output schema is the hard guarantee.
|
|
70
|
+
*/
|
|
71
|
+
export function buildEditPlanJsonSchema(opts) {
|
|
72
|
+
if (!opts?.planFirstMode)
|
|
73
|
+
return editPlanJsonSchema;
|
|
74
|
+
return {
|
|
75
|
+
...editPlanJsonSchema,
|
|
76
|
+
properties: {
|
|
77
|
+
...editPlanJsonSchema.properties,
|
|
78
|
+
intent: {
|
|
79
|
+
...editPlanJsonSchema.properties.intent,
|
|
80
|
+
enum: ["edit_plan"],
|
|
81
|
+
description: "Plan-first review mode: this MUST be \"edit_plan\". Clarification and read-only answers are not permitted — generate any missing copy and choose sensible defaults to produce a concrete, reviewable plan."
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// JSON Schema for intent parsing — used with output_config.format for
|
|
88
|
+
// constrained decoding (guaranteed valid JSON matching this schema).
|
|
89
|
+
// Hand-crafted to stay within the intersection of OpenAI strict mode and
|
|
90
|
+
// Anthropic json_schema constraints (no propertyNames, $ref, oneOf, etc.).
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
function nullable(schema) {
|
|
93
|
+
return { anyOf: [schema, { type: "null" }] };
|
|
94
|
+
}
|
|
95
|
+
const blockTypeEnumSchema = { type: "string", enum: [...allowedBlockTypes] };
|
|
96
|
+
export const intentJsonSchema = {
|
|
97
|
+
type: "object",
|
|
98
|
+
additionalProperties: false,
|
|
99
|
+
properties: {
|
|
100
|
+
action: { type: "string", enum: ["add", "move", "update", "remove", "info", "clarify"] },
|
|
101
|
+
target_block_ref: nullable({ type: "string" }),
|
|
102
|
+
target_block_type: nullable(blockTypeEnumSchema),
|
|
103
|
+
new_block_type: nullable(blockTypeEnumSchema),
|
|
104
|
+
position: nullable({ type: "string", enum: ["top", "bottom", "before", "after"] }),
|
|
105
|
+
anchor_block_ref: nullable({ type: "string" }),
|
|
106
|
+
summary: nullable({ type: "string" }),
|
|
107
|
+
assumption: nullable({ type: "string" }),
|
|
108
|
+
complexity: nullable({ type: "string", enum: ["simple", "standard", "complex"] })
|
|
109
|
+
},
|
|
110
|
+
required: ["action", "target_block_ref", "target_block_type", "new_block_type",
|
|
111
|
+
"position", "anchor_block_ref", "summary", "assumption", "complexity"]
|
|
112
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { PlannerSource } from "./provider-routing.ts";
|
|
2
|
+
import type { ParsedIntent } from "../nlp/deterministic-planner.ts";
|
|
3
|
+
import type { EditPlan, PageDoc, BlockManifest, Operation } from "@avocadostudio-ai/shared";
|
|
4
|
+
import type { TokenUsage } from "../telemetry/usage.ts";
|
|
5
|
+
import type { PlannerSchemaContextMeta } from "./planner.ts";
|
|
6
|
+
import type { DeferredNativeImageCall } from "./chat-pipeline-shared.ts";
|
|
7
|
+
import type { ToolRuntime } from "../tools/runtime.ts";
|
|
8
|
+
import type { ToolExecutionEvent } from "../tools/types.ts";
|
|
9
|
+
export type CommonParseIntentArgs = {
|
|
10
|
+
message: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
currentPage: PageDoc;
|
|
13
|
+
activeBlockId?: string;
|
|
14
|
+
activeBlockType?: string;
|
|
15
|
+
activeEditablePath?: string;
|
|
16
|
+
model: string;
|
|
17
|
+
log?: {
|
|
18
|
+
warn: (obj: Record<string, unknown>, msg: string) => void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type ThinkingEvent = {
|
|
22
|
+
type: "start";
|
|
23
|
+
} | {
|
|
24
|
+
type: "token";
|
|
25
|
+
text: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: "end";
|
|
28
|
+
durationMs: number;
|
|
29
|
+
};
|
|
30
|
+
export type CommonGeneratePlanArgs = {
|
|
31
|
+
message: string;
|
|
32
|
+
slug: string;
|
|
33
|
+
currentPage: PageDoc;
|
|
34
|
+
contextPack: ReturnType<typeof import("../nlp/deterministic-planner.ts").plannerContextPack>;
|
|
35
|
+
model: string;
|
|
36
|
+
history?: Array<{
|
|
37
|
+
role: "user" | "assistant";
|
|
38
|
+
content: string;
|
|
39
|
+
}>;
|
|
40
|
+
feedback?: string;
|
|
41
|
+
onToken?: (token: string) => void;
|
|
42
|
+
onThinking?: (event: ThinkingEvent) => void;
|
|
43
|
+
onFieldDraft?: (draft: {
|
|
44
|
+
blockId: string;
|
|
45
|
+
editablePath: string;
|
|
46
|
+
value: string;
|
|
47
|
+
}) => void;
|
|
48
|
+
onPlannedOp?: (op: Operation, index: number) => void;
|
|
49
|
+
onSummaryChunk?: (text: string) => void;
|
|
50
|
+
onChangeLogEntry?: (entry: string) => void;
|
|
51
|
+
onToolExecution?: (event: ToolExecutionEvent) => void;
|
|
52
|
+
onStatusUpdate?: (message: string) => void;
|
|
53
|
+
onImageProgress?: (event: {
|
|
54
|
+
percent: number;
|
|
55
|
+
stage: string;
|
|
56
|
+
}) => void;
|
|
57
|
+
toolRuntime?: ToolRuntime;
|
|
58
|
+
toolCallContext?: {
|
|
59
|
+
siteId: string;
|
|
60
|
+
sessionId: string;
|
|
61
|
+
userId?: string;
|
|
62
|
+
traceId: string;
|
|
63
|
+
gdriveFolderId?: string;
|
|
64
|
+
};
|
|
65
|
+
siteContextBlock?: string | null;
|
|
66
|
+
log?: {
|
|
67
|
+
warn: (obj: Record<string, unknown>, msg: string) => void;
|
|
68
|
+
};
|
|
69
|
+
forceFullSchemaContracts?: boolean;
|
|
70
|
+
componentsManifest?: BlockManifest;
|
|
71
|
+
lightweight?: boolean;
|
|
72
|
+
signal?: AbortSignal;
|
|
73
|
+
locale?: string;
|
|
74
|
+
/**
|
|
75
|
+
* True iff the planner is allowed to return needs_clarification asking the
|
|
76
|
+
* user whether a new image should come from Unsplash or AI generation. Set
|
|
77
|
+
* only when both sources are configured server-side AND no session-level
|
|
78
|
+
* preference is in effect. See chat-pipeline.ts for the computation and
|
|
79
|
+
* sectionImageSourceChoice in prompts.ts for how the rule is phrased.
|
|
80
|
+
*/
|
|
81
|
+
imageSourceChoiceOpen?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Enable adaptive thinking at the given effort (Anthropic). Ignored by
|
|
84
|
+
* providers that don't support it. Effort controls thinking depth and overall
|
|
85
|
+
* token spend — keep it modest for cost efficiency.
|
|
86
|
+
*/
|
|
87
|
+
thinking?: {
|
|
88
|
+
effort: PlannerEffort;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Effort levels accepted by the Messages API `output_config.effort` field on the
|
|
93
|
+
* stable SDK. `xhigh` is beta-only and intentionally excluded.
|
|
94
|
+
*/
|
|
95
|
+
export type PlannerEffort = "low" | "medium" | "high" | "max";
|
|
96
|
+
/**
|
|
97
|
+
* Map a legacy thinking token budget onto an effort level, preserving the
|
|
98
|
+
* "bigger budget → more thinking" intent of the CHAT_AUTO_REASONING_BUDGET knob
|
|
99
|
+
* while moving to the adaptive-thinking API. Deliberately cost-conscious: the
|
|
100
|
+
* default budget (2048) lands on "medium", not "high".
|
|
101
|
+
*/
|
|
102
|
+
export declare function budgetTokensToEffort(budgetTokens: number): PlannerEffort;
|
|
103
|
+
export type GeneratePlanResult = {
|
|
104
|
+
plan: EditPlan;
|
|
105
|
+
usage: TokenUsage;
|
|
106
|
+
schemaContext: PlannerSchemaContextMeta;
|
|
107
|
+
deferredNativeImageCalls?: DeferredNativeImageCall[];
|
|
108
|
+
};
|
|
109
|
+
export interface Planner {
|
|
110
|
+
readonly source: PlannerSource;
|
|
111
|
+
/** True when the provider supports native tool use for structured output. */
|
|
112
|
+
readonly supportsNativeTools: boolean;
|
|
113
|
+
parseIntent(args: CommonParseIntentArgs): Promise<ParsedIntent>;
|
|
114
|
+
generatePlan(args: CommonGeneratePlanArgs): Promise<GeneratePlanResult>;
|
|
115
|
+
}
|
|
116
|
+
export type PlannerRegistry = {
|
|
117
|
+
get(source: PlannerSource): Planner | null;
|
|
118
|
+
has(source: PlannerSource): boolean;
|
|
119
|
+
};
|
|
120
|
+
export declare function createPlannerRegistry(overrides?: Partial<Record<PlannerSource, Planner>>): PlannerRegistry;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { generatePlanWithOpenAI, parseIntentWithOpenAI, } from "./planner.js";
|
|
2
|
+
import { generatePlanWithAnthropic, parseIntentWithAnthropic, } from "./anthropic-planner.js";
|
|
3
|
+
import { generatePlanWithGemini, parseIntentWithGemini, } from "./gemini-planner.js";
|
|
4
|
+
/**
|
|
5
|
+
* Map a legacy thinking token budget onto an effort level, preserving the
|
|
6
|
+
* "bigger budget → more thinking" intent of the CHAT_AUTO_REASONING_BUDGET knob
|
|
7
|
+
* while moving to the adaptive-thinking API. Deliberately cost-conscious: the
|
|
8
|
+
* default budget (2048) lands on "medium", not "high".
|
|
9
|
+
*/
|
|
10
|
+
export function budgetTokensToEffort(budgetTokens) {
|
|
11
|
+
if (budgetTokens <= 1500)
|
|
12
|
+
return "low";
|
|
13
|
+
if (budgetTokens <= 8000)
|
|
14
|
+
return "medium";
|
|
15
|
+
if (budgetTokens <= 24000)
|
|
16
|
+
return "high";
|
|
17
|
+
return "max";
|
|
18
|
+
}
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Default implementations — thin adapters over existing functions.
|
|
21
|
+
// Each adapter strips fields the underlying provider function doesn't accept.
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const openAIPlanner = {
|
|
24
|
+
source: "openai",
|
|
25
|
+
supportsNativeTools: false,
|
|
26
|
+
async parseIntent(args) {
|
|
27
|
+
const { log: _log, ...rest } = args;
|
|
28
|
+
return parseIntentWithOpenAI(rest);
|
|
29
|
+
},
|
|
30
|
+
async generatePlan(args) {
|
|
31
|
+
// OpenAI doesn't yet support Anthropic-style thinking events — drop them.
|
|
32
|
+
const { onStatusUpdate: _s, onImageProgress: _i, log: _l, onThinking: _t, thinking: _th, ...rest } = args;
|
|
33
|
+
return generatePlanWithOpenAI(rest);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
const anthropicPlanner = {
|
|
37
|
+
source: "anthropic",
|
|
38
|
+
supportsNativeTools: true,
|
|
39
|
+
parseIntent: parseIntentWithAnthropic,
|
|
40
|
+
generatePlan: generatePlanWithAnthropic,
|
|
41
|
+
};
|
|
42
|
+
const geminiPlanner = {
|
|
43
|
+
source: "gemini",
|
|
44
|
+
supportsNativeTools: true,
|
|
45
|
+
parseIntent: parseIntentWithGemini,
|
|
46
|
+
async generatePlan(args) {
|
|
47
|
+
const { onThinking: _t, thinking: _th, ...rest } = args;
|
|
48
|
+
return generatePlanWithGemini(rest);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
export function createPlannerRegistry(overrides) {
|
|
52
|
+
const defaults = {
|
|
53
|
+
openai: openAIPlanner,
|
|
54
|
+
anthropic: anthropicPlanner,
|
|
55
|
+
gemini: geminiPlanner,
|
|
56
|
+
};
|
|
57
|
+
const merged = { ...defaults, ...(overrides ?? {}) };
|
|
58
|
+
return {
|
|
59
|
+
get(source) {
|
|
60
|
+
return merged[source] ?? null;
|
|
61
|
+
},
|
|
62
|
+
has(source) {
|
|
63
|
+
return merged[source] !== undefined;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|