wizards 0.5.7 → 0.5.9
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/apps/runtime/dist/agents/architect.js +13 -26
- package/apps/runtime/dist/agents/studio-assistant.js +19 -22
- package/apps/runtime/dist/agents/subscription.js +10 -9
- package/apps/runtime/dist/app.js +6 -6
- package/apps/runtime/dist/assistant/knows.js +10 -9
- package/apps/runtime/dist/connectors/external.js +3 -3
- package/apps/runtime/dist/connectors/index.js +23 -23
- package/apps/runtime/dist/connectors/via-account.js +6 -6
- package/apps/runtime/dist/documents/parse.js +3 -3
- package/apps/runtime/dist/engine/input.js +11 -11
- package/apps/runtime/dist/engine/requirements.js +7 -8
- package/apps/runtime/dist/engine/runner.js +10 -14
- package/apps/runtime/dist/engine/steps.js +6 -6
- package/apps/runtime/dist/engine/surface.js +2 -2
- package/apps/runtime/dist/film/step.js +5 -5
- package/apps/runtime/dist/harness/apple.js +2 -1
- package/apps/runtime/dist/harness/claude.js +2 -2
- package/apps/runtime/dist/harness/codex.js +2 -2
- package/apps/runtime/dist/harness/model.js +4 -5
- package/apps/runtime/dist/harness/terminal.js +4 -4
- package/apps/runtime/dist/media/conversation.js +18 -35
- package/apps/runtime/dist/media/transcribe.js +2 -1
- package/apps/runtime/dist/model-errors.js +1 -1
- package/apps/runtime/dist/models.js +32 -40
- package/apps/runtime/dist/plugins/runs.js +3 -5
- package/apps/runtime/dist/routes/api.js +9 -9
- package/apps/runtime/dist/routes/lang.js +14 -9
- package/apps/runtime/dist/routes/runs.js +5 -5
- package/apps/runtime/dist/routes/studio.js +38 -37
- package/apps/runtime/dist/services/access.js +4 -4
- package/apps/runtime/dist/services/architect.js +3 -12
- package/apps/runtime/dist/services/assistant-chats.js +2 -2
- package/apps/runtime/dist/services/brand.js +3 -3
- package/apps/runtime/dist/services/cloud.js +5 -5
- package/apps/runtime/dist/services/errors.js +2 -2
- package/apps/runtime/dist/services/knowledge-model.js +3 -3
- package/apps/runtime/dist/services/marketplace.js +3 -3
- package/apps/runtime/dist/services/package-file.js +9 -11
- package/apps/runtime/dist/services/package.js +8 -9
- package/apps/runtime/dist/services/profile.js +2 -1
- package/apps/runtime/dist/services/project-files.js +13 -13
- package/apps/runtime/dist/services/projects.js +7 -11
- package/apps/runtime/dist/services/runners.js +4 -4
- package/apps/runtime/dist/services/runs.js +7 -10
- package/apps/runtime/dist/services/shares.js +2 -2
- package/apps/runtime/dist/services/site.js +8 -11
- package/apps/runtime/dist/services/space-categories.js +7 -7
- package/apps/runtime/dist/services/space-data.js +20 -20
- package/apps/runtime/dist/services/spaces.js +7 -9
- package/apps/runtime/dist/services/wizards.js +11 -13
- package/apps/runtime/dist/store/index.js +2 -2
- package/apps/runtime/dist/texts.js +195 -0
- package/apps/runtime/dist/tools/plugin.js +7 -3
- package/apps/runtime/dist/widgets/step.js +2 -2
- package/apps/web/dist/assets/AboutDialog-CpI-cGpz.js +1 -0
- package/apps/web/dist/assets/{ChangelogDialog-rAtYZjxz.js → ChangelogDialog-BW56Y5UR.js} +1 -1
- package/apps/web/dist/assets/ChatView-CH8U-tRy.js +10 -0
- package/apps/web/dist/assets/EditorPage-Be5J_y4F.js +3 -0
- package/apps/web/dist/assets/{FlowPreview--3-yI51e.js → FlowPreview-CzmH4JUQ.js} +1 -1
- package/apps/web/dist/assets/{Harness-B9tvFe0U.js → Harness-CJKWO3AK.js} +2 -2
- package/apps/web/dist/assets/{NewWizardChannels-BxrBhC9U.js → NewWizardChannels-Ca2niMTY.js} +1 -1
- package/apps/web/dist/assets/NewWizardPage-D5gi4TYE.js +7 -0
- package/apps/web/dist/assets/{OnboardingPage-DPdH9sSj.js → OnboardingPage-Bm-c-D21.js} +1 -1
- package/apps/web/dist/assets/ProjectPage-C8nJCBZP.js +1 -0
- package/apps/web/dist/assets/{PublicRunner-Bv3TMKw4.js → PublicRunner-anxg3Rxz.js} +1 -1
- package/apps/web/dist/assets/{ReadOnly-CmqIrOAR.js → ReadOnly-i-6WBMSE.js} +1 -1
- package/apps/web/dist/assets/RunDrawer-4yvfW_2c.js +4 -0
- package/apps/web/dist/assets/{RunnerView-Cd1VAlIA.js → RunnerView-BkWQBa_M.js} +1 -1
- package/apps/web/dist/assets/SettingsPage-NL8r9S6R.js +1 -0
- package/apps/web/dist/assets/SetupPage-Crcfx4-p.js +1 -0
- package/apps/web/dist/assets/{SharePage-BT80wI1I.js → SharePage-CDEAtmBC.js} +1 -1
- package/apps/web/dist/assets/changelog-BGBuldNF.js +1 -0
- package/apps/web/dist/assets/{esm-BTVd6EFo.js → esm-BF1nonbH.js} +1 -1
- package/apps/web/dist/assets/index-C74LSJ-W.js +14 -0
- package/apps/web/dist/assets/{lock-ByHFI96G.js → lock-DVvM6IsA.js} +1 -1
- package/apps/web/dist/assets/{phone-KPwxAM1R.js → phone-3fG1okFs.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-K5bg3QE3.js → settings-menu-D9fbi1Z0.js} +1 -1
- package/apps/web/dist/assets/ui-EuR3jezP.js +134 -0
- package/apps/web/dist/assets/{upload-BsIL8tNR.js → upload-BsMUhEfX.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/apps/web/dist/mcp/flow.html +77 -77
- package/bin/wizards.mjs +15 -2
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +26 -9
- package/node_modules/@engenty-wizards/shared/dist/definition.js +125 -3
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +1 -1
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +9 -8
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +6 -6
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +78 -205
- package/node_modules/@engenty-wizards/shared/dist/marketplace.js +167 -68
- package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +3 -6
- package/node_modules/@engenty-wizards/shared/dist/projects.js +9 -9
- package/node_modules/@engenty-wizards/shared/dist/providers.d.ts +33 -7
- package/node_modules/@engenty-wizards/shared/dist/providers.js +88 -37
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +298 -365
- package/node_modules/@engenty-wizards/shared/dist/run.js +582 -240
- package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +36 -0
- package/node_modules/@engenty-wizards/shared/dist/texts.js +46 -0
- package/package.json +5 -1
- package/apps/web/dist/assets/AboutDialog-t9bayaIs.js +0 -1
- package/apps/web/dist/assets/ChatView-C3VqLT98.js +0 -10
- package/apps/web/dist/assets/EditorPage-D3Ef24b9.js +0 -3
- package/apps/web/dist/assets/NewWizardPage-C1_hsQPr.js +0 -7
- package/apps/web/dist/assets/ProjectPage-P40R1cPE.js +0 -1
- package/apps/web/dist/assets/RunDrawer-9qG1G-OY.js +0 -4
- package/apps/web/dist/assets/SettingsPage-DFz4UMfo.js +0 -1
- package/apps/web/dist/assets/SetupPage-B0UBNMB9.js +0 -1
- package/apps/web/dist/assets/changelog-BpSBMjpm.js +0 -1
- package/apps/web/dist/assets/index-D8vwgldH.js +0 -14
- package/apps/web/dist/assets/ui-4bQx9I1f.js +0 -134
|
@@ -15,6 +15,7 @@ import { deleteFile, listFiles, readFileText, writeFile } from "../services/file
|
|
|
15
15
|
import { checkDraftWidget } from "../services/widgets.js";
|
|
16
16
|
import { editWizard, ownedWizard, writeDraft } from "../services/wizards.js";
|
|
17
17
|
import { currentTenant } from "../tenants/tenant.js";
|
|
18
|
+
import { serverText } from "../texts.js";
|
|
18
19
|
import { assertPublicUrl, safeFetch } from "../tools/net-guard.js";
|
|
19
20
|
import { runScript } from "../widgets/script.js";
|
|
20
21
|
import { thoughtLine } from "./thought.js";
|
|
@@ -54,7 +55,7 @@ HOW YOU WORK
|
|
|
54
55
|
}
|
|
55
56
|
/** Turns a tool call into the line the admin sees while it runs. */
|
|
56
57
|
function activity(tool, args, lang = "en") {
|
|
57
|
-
const
|
|
58
|
+
const say = (key, params) => serverText(lang, key, params);
|
|
58
59
|
const host = (u) => {
|
|
59
60
|
try {
|
|
60
61
|
return new URL(String(u)).hostname;
|
|
@@ -66,42 +67,28 @@ function activity(tool, args, lang = "en") {
|
|
|
66
67
|
switch (tool) {
|
|
67
68
|
case "replace_wizard":
|
|
68
69
|
case "edit_wizard":
|
|
69
|
-
return
|
|
70
|
+
return say("doingFlow");
|
|
70
71
|
case "write_file":
|
|
71
72
|
return args.path
|
|
72
|
-
?
|
|
73
|
-
|
|
74
|
-
: `Writing ${String(args.path)} …`
|
|
75
|
-
: de
|
|
76
|
-
? "Schreibt eine Datei …"
|
|
77
|
-
: "Writing a file …";
|
|
73
|
+
? say("doingWriteFile", { path: String(args.path) })
|
|
74
|
+
: say("doingWriteAFile");
|
|
78
75
|
case "download_files":
|
|
79
|
-
return
|
|
76
|
+
return say("doingDownload");
|
|
80
77
|
case "web_fetch":
|
|
81
|
-
return args.url
|
|
82
|
-
? de
|
|
83
|
-
? `Liest ${host(args.url)} …`
|
|
84
|
-
: `Reading ${host(args.url)} …`
|
|
85
|
-
: de
|
|
86
|
-
? "Liest im Web …"
|
|
87
|
-
: "Reading the web …";
|
|
78
|
+
return args.url ? say("doingReadSite", { host: host(args.url) }) : say("doingReadWeb");
|
|
88
79
|
case "web_search":
|
|
89
|
-
return
|
|
80
|
+
return say("doingWebSearch");
|
|
90
81
|
case "check_widget":
|
|
91
|
-
return
|
|
82
|
+
return say("doingTestWidget");
|
|
92
83
|
case "run_script":
|
|
93
84
|
return args.output
|
|
94
|
-
?
|
|
95
|
-
|
|
96
|
-
: `Preparing ${String(args.output)} …`
|
|
97
|
-
: de
|
|
98
|
-
? "Rechnet …"
|
|
99
|
-
: "Calculating …";
|
|
85
|
+
? say("doingPrepare", { output: String(args.output) })
|
|
86
|
+
: say("doingCalculate");
|
|
100
87
|
case "list_files":
|
|
101
88
|
case "read_file":
|
|
102
|
-
return
|
|
89
|
+
return say("doingLookFiles");
|
|
103
90
|
case "delete_file":
|
|
104
|
-
return
|
|
91
|
+
return say("doingTidyFiles");
|
|
105
92
|
default:
|
|
106
93
|
return null;
|
|
107
94
|
}
|
|
@@ -15,6 +15,7 @@ import { documentText } from "../services/project-index.js";
|
|
|
15
15
|
import { ownedProject, updateProject } from "../services/projects.js";
|
|
16
16
|
import { categoryRows } from "../services/space-categories.js";
|
|
17
17
|
import { currentTenant } from "../tenants/tenant.js";
|
|
18
|
+
import { serverText } from "../texts.js";
|
|
18
19
|
import { assistantPageOf, assistantToolsOf } from "../tools/plugin.js";
|
|
19
20
|
import { readWebsite } from "./website.js";
|
|
20
21
|
/** How a message written meanwhile reaches the model. */
|
|
@@ -60,19 +61,19 @@ HOW YOU WORK
|
|
|
60
61
|
- Call independent tools together. Work in few steps.
|
|
61
62
|
- Finish with one to three sentences: what you did or found, what is still open, and at most one question.`;
|
|
62
63
|
const LABELS = {
|
|
63
|
-
save_logo:
|
|
64
|
-
save_file:
|
|
65
|
-
set_logo_sections:
|
|
66
|
-
set_asset_sections:
|
|
67
|
-
set_typography:
|
|
68
|
-
set_gradients:
|
|
69
|
-
set_rules:
|
|
70
|
-
set_profile:
|
|
71
|
-
set_facts:
|
|
72
|
-
set_colors:
|
|
73
|
-
look_at_file:
|
|
74
|
-
describe_file:
|
|
75
|
-
web_search:
|
|
64
|
+
save_logo: "doingSaveLogo",
|
|
65
|
+
save_file: "doingSaveFile",
|
|
66
|
+
set_logo_sections: "doingSetLogoSections",
|
|
67
|
+
set_asset_sections: "doingSetAssetSections",
|
|
68
|
+
set_typography: "doingSetTypography",
|
|
69
|
+
set_gradients: "doingSetGradients",
|
|
70
|
+
set_rules: "doingSetRules",
|
|
71
|
+
set_profile: "doingSetProfile",
|
|
72
|
+
set_facts: "doingSetFacts",
|
|
73
|
+
set_colors: "doingSetColors",
|
|
74
|
+
look_at_file: "doingLookAtFile",
|
|
75
|
+
describe_file: "doingDescribeFile",
|
|
76
|
+
web_search: "doingWebSearch",
|
|
76
77
|
};
|
|
77
78
|
function activity(tool, args, lang) {
|
|
78
79
|
const host = (u) => {
|
|
@@ -85,20 +86,16 @@ function activity(tool, args, lang) {
|
|
|
85
86
|
};
|
|
86
87
|
if (tool === "read_website") {
|
|
87
88
|
const at = args.url ? host(args.url) : "";
|
|
88
|
-
return
|
|
89
|
-
? at
|
|
90
|
-
|
|
91
|
-
: "Liest die Website …"
|
|
92
|
-
: at
|
|
93
|
-
? `Reading ${at} …`
|
|
94
|
-
: "Reading the website …";
|
|
89
|
+
return at
|
|
90
|
+
? serverText(lang, "doingReadSite", { host: at })
|
|
91
|
+
: serverText(lang, "doingReadWebsite");
|
|
95
92
|
}
|
|
96
93
|
const key = tool === "save_file" && args.kind === "logo"
|
|
97
94
|
? "save_logo"
|
|
98
95
|
: tool === "remove_facts"
|
|
99
96
|
? "set_facts"
|
|
100
97
|
: tool;
|
|
101
|
-
return LABELS[key]
|
|
98
|
+
return LABELS[key] ? serverText(lang, LABELS[key]) : null;
|
|
102
99
|
}
|
|
103
100
|
async function attempt(run) {
|
|
104
101
|
try {
|
|
@@ -886,7 +883,7 @@ export async function runStudioAssistant(input) {
|
|
|
886
883
|
else if (chunk.type === "tool-call") {
|
|
887
884
|
// The model's own search has no tool of ours that could say so.
|
|
888
885
|
if (payload.toolName === "web_search") {
|
|
889
|
-
input.onActivity?.(LABELS.web_search
|
|
886
|
+
input.onActivity?.(serverText(input.lang, LABELS.web_search));
|
|
890
887
|
}
|
|
891
888
|
// Keep what it says before and after a tool call apart.
|
|
892
889
|
if (reply.trim() && !reply.endsWith("\n\n")) {
|
|
@@ -9,6 +9,7 @@ import { detectHarness, signedOut } from "../harness/index.js";
|
|
|
9
9
|
import { localModelSettings } from "../models.js";
|
|
10
10
|
import { ServiceError } from "../services/errors.js";
|
|
11
11
|
import { deleteSetting, readSetting, writeSetting } from "../settings.js";
|
|
12
|
+
import { serverText } from "../texts.js";
|
|
12
13
|
import { thoughtLine } from "./thought.js";
|
|
13
14
|
/** The AI clients installed on this machine whose subscription can answer the studio chat. */
|
|
14
15
|
export async function subscriptionClients() {
|
|
@@ -38,18 +39,18 @@ const SYSTEM = (wizardId) => [
|
|
|
38
39
|
].join("\n");
|
|
39
40
|
const BUILDING = /edit_wizard|write_wizard|write_file|delete_file|create_wizard/;
|
|
40
41
|
const ACTIVITY = [
|
|
41
|
-
[/get_authoring_guide/,
|
|
42
|
-
[/get_starter|list_starters/,
|
|
43
|
-
[/get_wizard|list_files|read_file/,
|
|
44
|
-
[/write_file|delete_file/,
|
|
45
|
-
[/edit_wizard|write_wizard/,
|
|
46
|
-
[/check_widget|preview/,
|
|
47
|
-
[/start_test_run|get_test_run/,
|
|
48
|
-
[/find_connectors|import_connector/,
|
|
42
|
+
[/get_authoring_guide/, "doingGuide"],
|
|
43
|
+
[/get_starter|list_starters/, "doingTemplate"],
|
|
44
|
+
[/get_wizard|list_files|read_file/, "doingReadWizard"],
|
|
45
|
+
[/write_file|delete_file/, "doingWriteFiles"],
|
|
46
|
+
[/edit_wizard|write_wizard/, "doingRebuild"],
|
|
47
|
+
[/check_widget|preview/, "doingCheckWidget"],
|
|
48
|
+
[/start_test_run|get_test_run/, "doingTestWizard"],
|
|
49
|
+
[/find_connectors|import_connector/, "doingFindService"],
|
|
49
50
|
];
|
|
50
51
|
/** The activity for one tool call, naming the file or service it is about when it says. */
|
|
51
52
|
function activity(name, args, lang = "en") {
|
|
52
|
-
const label = ACTIVITY.find(([re]) => re.test(name))?.[1]
|
|
53
|
+
const label = serverText(lang, ACTIVITY.find(([re]) => re.test(name))?.[1] ?? "doingWork");
|
|
53
54
|
const about = [args.path, args.query].find((v) => typeof v === "string" && v.trim());
|
|
54
55
|
return about ? `${label}: ${String(about)} …` : `${label} …`;
|
|
55
56
|
}
|
package/apps/runtime/dist/app.js
CHANGED
|
@@ -23,7 +23,7 @@ import { PLUGIN_NAME, pluginArchive, pluginMarketplace } from "./plugin.js";
|
|
|
23
23
|
import { apiRoutes } from "./routes/api.js";
|
|
24
24
|
import { browserReport, localDebugRoutes } from "./routes/debug.js";
|
|
25
25
|
import { internalRoutes } from "./routes/internal.js";
|
|
26
|
-
import {
|
|
26
|
+
import { notFoundAnswer, requestLang, say } from "./routes/lang.js";
|
|
27
27
|
import { marketplaceGuest, marketplaceStudio } from "./routes/marketplace.js";
|
|
28
28
|
import { publicPluginRoutes } from "./routes/plugin-public.js";
|
|
29
29
|
import { pluginRoutes } from "./routes/plugins.js";
|
|
@@ -44,13 +44,13 @@ app.onError((err, c) => {
|
|
|
44
44
|
return c.json(err.toJSON(requestLang(c)), err.status);
|
|
45
45
|
}
|
|
46
46
|
if (err instanceof ZodError) {
|
|
47
|
-
return c.json({ error:
|
|
47
|
+
return c.json({ error: say(c, "invalidInput"), issues: err.issues }, 400);
|
|
48
48
|
}
|
|
49
49
|
if (err instanceof HTTPException) {
|
|
50
50
|
return err.getResponse();
|
|
51
51
|
}
|
|
52
52
|
console.error(err);
|
|
53
|
-
return c.json({ error:
|
|
53
|
+
return c.json({ error: say(c, "internalError") }, 500);
|
|
54
54
|
});
|
|
55
55
|
// --- who may talk to this server at all ---------------------------------------------
|
|
56
56
|
// A runtime that runs alone listens on the loopback interface. A web page in the person's
|
|
@@ -202,13 +202,13 @@ if (serves.studio) {
|
|
|
202
202
|
const user = await principalOf(c);
|
|
203
203
|
if (!user) {
|
|
204
204
|
return c.json({
|
|
205
|
-
error:
|
|
205
|
+
error: say(c, "notSignedIn"),
|
|
206
206
|
code: "unauthorized",
|
|
207
207
|
}, 401);
|
|
208
208
|
}
|
|
209
209
|
if ((await tenantStatus(user.tenantId)) === "suspended") {
|
|
210
210
|
return c.json({
|
|
211
|
-
error:
|
|
211
|
+
error: say(c, "accountSuspended"),
|
|
212
212
|
code: "suspended",
|
|
213
213
|
}, 403);
|
|
214
214
|
}
|
|
@@ -227,7 +227,7 @@ if (serves.runner) {
|
|
|
227
227
|
// answers are text; an upload is a photo, a recording or a clip from a phone (routes/delivery.ts).
|
|
228
228
|
const tooLarge = (max) => bodyLimit({
|
|
229
229
|
maxSize: max,
|
|
230
|
-
onError: (c) => c.json({ error:
|
|
230
|
+
onError: (c) => c.json({ error: say(c, "tooLarge"), code: "too_large" }, 413),
|
|
231
231
|
});
|
|
232
232
|
const answers = tooLarge(4 * 1024 * 1024);
|
|
233
233
|
const upload = tooLarge(48 * 1024 * 1024);
|
|
@@ -13,6 +13,7 @@ import { pluginToolsOf } from "../plugins/registry.js";
|
|
|
13
13
|
import { earlierChats, readChat, searchChats } from "../services/assistant-chats.js";
|
|
14
14
|
import { asLang, marketplaceDetail, searchMarketplace } from "../services/marketplace.js";
|
|
15
15
|
import { listWizards } from "../services/wizards.js";
|
|
16
|
+
import { serverText } from "../texts.js";
|
|
16
17
|
import { attempt } from "../tools/shared.js";
|
|
17
18
|
import { readDoc, searchDocs } from "./docs.js";
|
|
18
19
|
/** Where the account lives: the runtime's Manage-App, or the account a local install links. */
|
|
@@ -45,7 +46,7 @@ export function knowsTools(ctx) {
|
|
|
45
46
|
description: "Search the engenty wizards user guide and plugin guide of this installed version. Gives the best sections with an excerpt and their engenty.ai/docs link. Use it before you explain how something works.",
|
|
46
47
|
inputSchema: z.object({ query: z.string().min(2).max(200) }),
|
|
47
48
|
execute: async ({ query }) => {
|
|
48
|
-
ctx.doing(ctx.lang
|
|
49
|
+
ctx.doing(serverText(ctx.lang, "doingReadGuide"));
|
|
49
50
|
return { hits: searchDocs(query) };
|
|
50
51
|
},
|
|
51
52
|
}),
|
|
@@ -57,7 +58,7 @@ export function knowsTools(ctx) {
|
|
|
57
58
|
from: z.number().int().min(0).optional(),
|
|
58
59
|
}),
|
|
59
60
|
execute: async ({ page, from }) => {
|
|
60
|
-
ctx.doing(ctx.lang
|
|
61
|
+
ctx.doing(serverText(ctx.lang, "doingReadGuide"));
|
|
61
62
|
return readDoc(page, from ?? 0);
|
|
62
63
|
},
|
|
63
64
|
}),
|
|
@@ -66,7 +67,7 @@ export function knowsTools(ctx) {
|
|
|
66
67
|
description: "The authoring guide the wizard editor and AI apps build with: how a wizard is written (steps, fields, flows, tools, outputs, model classes). Long: read it in parts with `from`.",
|
|
67
68
|
inputSchema: z.object({ from: z.number().int().min(0).optional() }),
|
|
68
69
|
execute: ({ from }) => attempt(async () => {
|
|
69
|
-
ctx.doing(ctx.lang
|
|
70
|
+
ctx.doing(serverText(ctx.lang, "doingAuthoringGuide"));
|
|
70
71
|
const guide = authoringGuide(ctx.project?.mcpServers ?? [], ctx.project ? await listConnectors(ctx.project.id) : [], await pluginToolsOf(user.tenantId));
|
|
71
72
|
const start = Math.min(from ?? 0, guide.length);
|
|
72
73
|
return {
|
|
@@ -80,7 +81,7 @@ export function knowsTools(ctx) {
|
|
|
80
81
|
description: "Search the gallery of wizard templates (engenty.ai/wizards and the plugins' starters): title, pitch, what it needs that this install has no model for, and its price per run in credits.",
|
|
81
82
|
inputSchema: z.object({ query: z.string().max(200).optional() }),
|
|
82
83
|
execute: ({ query }) => attempt(async () => {
|
|
83
|
-
ctx.doing(ctx.lang
|
|
84
|
+
ctx.doing(serverText(ctx.lang, "doingGallery"));
|
|
84
85
|
const hits = await searchMarketplace({
|
|
85
86
|
q: query ?? "",
|
|
86
87
|
lang: asLang(ctx.lang),
|
|
@@ -146,7 +147,7 @@ export function knowsTools(ctx) {
|
|
|
146
147
|
description: "The plans teams can be on (Free, Pro, Team): price a month, monthly credits, limits, and the credit packages to buy on top. Live from the account service.",
|
|
147
148
|
inputSchema: z.object({}),
|
|
148
149
|
execute: () => attempt(async () => {
|
|
149
|
-
ctx.doing(ctx.lang
|
|
150
|
+
ctx.doing(serverText(ctx.lang, "doingPlans"));
|
|
150
151
|
const plans = await publicPlans(accountBase());
|
|
151
152
|
return { ...plans, billingPage: `${accountBase()}/billing` };
|
|
152
153
|
}),
|
|
@@ -156,7 +157,7 @@ export function knowsTools(ctx) {
|
|
|
156
157
|
description: "The person, their team, their role, the team's plan, the credit balance and credits that end on a date.",
|
|
157
158
|
inputSchema: z.object({}),
|
|
158
159
|
execute: () => attempt(async () => {
|
|
159
|
-
ctx.doing(ctx.lang
|
|
160
|
+
ctx.doing(serverText(ctx.lang, "doingAccount"));
|
|
160
161
|
if (managed) {
|
|
161
162
|
const info = await tenantInfo(user.tenantId, true);
|
|
162
163
|
return {
|
|
@@ -194,7 +195,7 @@ export function knowsTools(ctx) {
|
|
|
194
195
|
description: "Credits the team used per month (the last three), and the runs and wizards that cost the most.",
|
|
195
196
|
inputSchema: z.object({}),
|
|
196
197
|
execute: () => attempt(async () => {
|
|
197
|
-
ctx.doing(ctx.lang
|
|
198
|
+
ctx.doing(serverText(ctx.lang, "doingUsage"));
|
|
198
199
|
if (!(managed || (await linkedAccount()))) {
|
|
199
200
|
return { linked: false, note: NOT_LINKED };
|
|
200
201
|
}
|
|
@@ -296,7 +297,7 @@ export function knowsTools(ctx) {
|
|
|
296
297
|
description: "What thinks and makes for this install, per model class: an installed AI client, an own key, a local model, credits, or nothing (with the problem). Also which AI clients are installed and signed in.",
|
|
297
298
|
inputSchema: z.object({}),
|
|
298
299
|
execute: () => attempt(async () => {
|
|
299
|
-
ctx.doing(ctx.lang
|
|
300
|
+
ctx.doing(serverText(ctx.lang, "doingModels"));
|
|
300
301
|
return {
|
|
301
302
|
classes: waysIn(await classWays(), "en"),
|
|
302
303
|
clients: managed
|
|
@@ -315,7 +316,7 @@ export function knowsTools(ctx) {
|
|
|
315
316
|
description: "Search the person's earlier chats with you (their messages and summaries) for words: what was asked, changed or decided before.",
|
|
316
317
|
inputSchema: z.object({ query: z.string().min(3).max(200) }),
|
|
317
318
|
execute: ({ query }) => attempt(async () => {
|
|
318
|
-
ctx.doing(ctx.lang
|
|
319
|
+
ctx.doing(serverText(ctx.lang, "doingEarlierChats"));
|
|
319
320
|
const hits = (await searchChats(user, query)).filter((h) => h.chatId !== ctx.chatId);
|
|
320
321
|
return {
|
|
321
322
|
hits,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
2
2
|
import { and, asc, eq } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { db, schema } from "../db/client.js";
|
|
@@ -275,7 +275,7 @@ export async function importConnector(userId, projectId, input) {
|
|
|
275
275
|
await requireWritableProject(projectId);
|
|
276
276
|
await requireAdmin();
|
|
277
277
|
if (await load(projectId, input.id)) {
|
|
278
|
-
throw new ServiceError("invalid",
|
|
278
|
+
throw new ServiceError("invalid", note("connectorAlreadyExistsSpace", { id: input.id }));
|
|
279
279
|
}
|
|
280
280
|
try {
|
|
281
281
|
const { discover, surface, prepared } = await prepare(input);
|
|
@@ -352,7 +352,7 @@ export async function refreshConnector(projectId, id, accessToken) {
|
|
|
352
352
|
await requireWritableProject(projectId);
|
|
353
353
|
const record = await load(projectId, id);
|
|
354
354
|
if (!record) {
|
|
355
|
-
throw new ServiceError("not_found",
|
|
355
|
+
throw new ServiceError("not_found", note("connectorNotExist"));
|
|
356
356
|
}
|
|
357
357
|
try {
|
|
358
358
|
const { surface } = record.registry_surface_slug
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isLang } from "@engenty-wizards/shared/definition";
|
|
2
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
2
3
|
import { eq } from "drizzle-orm";
|
|
3
4
|
import { db, schema } from "../db/client.js";
|
|
4
5
|
import { buildAuthorizationUrl, createOAuth2Pkce, exchangeAuthorizationCode, refreshAccessToken, } from "../engenty/connections-sdk/oauth2.js";
|
|
@@ -7,23 +8,21 @@ import { env } from "../env.js";
|
|
|
7
8
|
import { NotedError } from "../model-errors.js";
|
|
8
9
|
import { seal, unseal } from "../secrets/crypto.js";
|
|
9
10
|
import { deleteSecret, getSecret, putSecret } from "../store/index.js";
|
|
11
|
+
import { serverText } from "../texts.js";
|
|
10
12
|
import { connectorFetch, MAIL_CONNECTORS, resolveEnv, usable, viaAccount } from "./builtin.js";
|
|
11
13
|
import { resolveConnector } from "./external.js";
|
|
12
14
|
import { AccountConnectError, redeemTicket, refreshThroughAccount, startThroughAccount, } from "./via-account.js";
|
|
13
15
|
/** The connectors a person can pick for each kind of connection. */
|
|
14
16
|
const CONNECTORS = { mail: MAIL_CONNECTORS };
|
|
15
|
-
const HINTS = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
email: { label: "E-Mail-Adresse", placeholder: "name@firma.at" },
|
|
25
|
-
password: { label: "Passwort oder App-Passwort" },
|
|
26
|
-
host: { label: "IMAP-Server", placeholder: "leer lassen bei Gmail, GMX, iCloud …" },
|
|
17
|
+
const HINTS = { imap: "imapHint" };
|
|
18
|
+
/** The built-in connectors' fields in each language; their definitions say them in English. */
|
|
19
|
+
const FIELD_WORDS = {
|
|
20
|
+
de: {
|
|
21
|
+
imap: {
|
|
22
|
+
email: { label: "E-Mail-Adresse", placeholder: "name@firma.at" },
|
|
23
|
+
password: { label: "Passwort oder App-Passwort" },
|
|
24
|
+
host: { label: "IMAP-Server", placeholder: "leer lassen bei Gmail, GMX, iCloud …" },
|
|
25
|
+
},
|
|
27
26
|
},
|
|
28
27
|
};
|
|
29
28
|
/**
|
|
@@ -67,10 +66,11 @@ export async function connectorOptions(connection, projectId, lang = "en") {
|
|
|
67
66
|
id: c.id,
|
|
68
67
|
name: c.name,
|
|
69
68
|
auth: "api_key",
|
|
70
|
-
fields:
|
|
71
|
-
|
|
72
|
-
: c.
|
|
73
|
-
|
|
69
|
+
fields: c.auth.apiKey.fields.map((f) => ({
|
|
70
|
+
...f,
|
|
71
|
+
...(lang === "en" ? undefined : FIELD_WORDS[lang]?.[c.id]?.[f.key]),
|
|
72
|
+
})),
|
|
73
|
+
hint: HINTS[c.id] && serverText(lang, HINTS[c.id]),
|
|
74
74
|
}
|
|
75
75
|
: { id: c.id, name: c.name, auth: "oauth2" });
|
|
76
76
|
}
|
|
@@ -157,7 +157,7 @@ export async function startOAuth(scope, projectId, runId, connection, connectorI
|
|
|
157
157
|
/** The language a sign-in was started in, a wizard's or a plugin's; null where it names none. */
|
|
158
158
|
export function oauthStateLang(rawState) {
|
|
159
159
|
const lang = unseal(rawState)?.lang;
|
|
160
|
-
return lang
|
|
160
|
+
return isLang(lang) ? lang : null;
|
|
161
161
|
}
|
|
162
162
|
/** The run an OAuth callback belongs to; its tenant is looked up before the state is used. */
|
|
163
163
|
export function oauthStateRun(rawState) {
|
|
@@ -214,7 +214,7 @@ export async function connectWithCredentials(scope, projectId, connection, conne
|
|
|
214
214
|
for (const field of connector.auth.apiKey.fields) {
|
|
215
215
|
const value = String(values[field.key] ?? "").trim();
|
|
216
216
|
if (!value && field.required !== false) {
|
|
217
|
-
throw new ConnectError(
|
|
217
|
+
throw new ConnectError(note("fieldMissing", { label: field.label }));
|
|
218
218
|
}
|
|
219
219
|
if (value) {
|
|
220
220
|
credentials[field.key] = value.slice(0, 500);
|
|
@@ -244,16 +244,16 @@ function connectFailure(err) {
|
|
|
244
244
|
const host = e.imapHost ? ` (${e.imapHost})` : "";
|
|
245
245
|
if (e.authenticationFailed) {
|
|
246
246
|
const answer = e.responseText?.slice(0, 160);
|
|
247
|
-
return
|
|
247
|
+
return note("signInRefused", { host, answer: answer ? note("serverSaid", { answer }) : "" });
|
|
248
248
|
}
|
|
249
249
|
if (e.code === "ENOTFOUND") {
|
|
250
|
-
return
|
|
250
|
+
return note("mailServerNotExist", { host });
|
|
251
251
|
}
|
|
252
252
|
if (e.code === "ETIMEDOUT" || e.code === "ETIMEOUT" || e.code === "ECONNREFUSED") {
|
|
253
|
-
return
|
|
253
|
+
return note("mailServerNotResponding", { host });
|
|
254
254
|
}
|
|
255
255
|
const detail = String(e.message ?? err).slice(0, 200);
|
|
256
|
-
return
|
|
256
|
+
return note("connectingNotWork", { host, detail });
|
|
257
257
|
}
|
|
258
258
|
export function disconnect(scope, connectionId) {
|
|
259
259
|
return deleteSecret(scope, slot(connectionId));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
2
2
|
import { accountToken } from "../auth/account.js";
|
|
3
3
|
import { env } from "../env.js";
|
|
4
4
|
import { NotedError } from "../model-errors.js";
|
|
@@ -26,7 +26,7 @@ export async function googleThroughAccount() {
|
|
|
26
26
|
async function call(path, body) {
|
|
27
27
|
const token = await accountToken();
|
|
28
28
|
if (!token) {
|
|
29
|
-
throw new AccountConnectError(
|
|
29
|
+
throw new AccountConnectError(note("connectEngentyAccountFirst"));
|
|
30
30
|
}
|
|
31
31
|
const res = await fetch(`${base()}${path}`, {
|
|
32
32
|
method: "POST",
|
|
@@ -35,15 +35,15 @@ async function call(path, body) {
|
|
|
35
35
|
signal: AbortSignal.timeout(20_000),
|
|
36
36
|
}).catch(() => null);
|
|
37
37
|
if (!res) {
|
|
38
|
-
throw new AccountConnectError(
|
|
38
|
+
throw new AccountConnectError(note("engentyAccountNotReached"));
|
|
39
39
|
}
|
|
40
40
|
const data = (await res.json().catch(() => ({})));
|
|
41
41
|
if (!res.ok) {
|
|
42
42
|
throw new AccountConnectError(data.code === "invalid_grant"
|
|
43
|
-
?
|
|
43
|
+
? note("googleNoLongerAccepts")
|
|
44
44
|
: data.code === "not_configured"
|
|
45
|
-
?
|
|
46
|
-
:
|
|
45
|
+
? note("googleNotConnectedThrough")
|
|
46
|
+
: note("viaAccountFailed", { code: data.code ?? res.status }));
|
|
47
47
|
}
|
|
48
48
|
return data;
|
|
49
49
|
}
|
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { existsSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
6
6
|
import { generateText, Output } from "ai";
|
|
7
7
|
import PostalMime from "postal-mime";
|
|
8
8
|
import { z } from "zod";
|
|
@@ -170,7 +170,7 @@ async function read(input, opts) {
|
|
|
170
170
|
const vision = new VisionProvider(opts.charge, opts.signal, opts.call);
|
|
171
171
|
if (mime.startsWith("image/")) {
|
|
172
172
|
if (!vision.canConvert(mime)) {
|
|
173
|
-
throw new UnreadableDocument(
|
|
173
|
+
throw new UnreadableDocument(note("imageTypeNotReadable", { mime }));
|
|
174
174
|
}
|
|
175
175
|
const result = await vision.convert(data, name, mime);
|
|
176
176
|
return { markdown: result.markdown, pages: 1, via: "vision" };
|
|
@@ -214,7 +214,7 @@ async function read(input, opts) {
|
|
|
214
214
|
if (mime === "application/json" || mime.startsWith("text/")) {
|
|
215
215
|
return { markdown: text(), pages: null, via: "text" };
|
|
216
216
|
}
|
|
217
|
-
throw new UnreadableDocument(
|
|
217
|
+
throw new UnreadableDocument(note("fileNotReadable", { name, mime }));
|
|
218
218
|
}
|
|
219
219
|
// --- structured extraction -----------------------------------------------------
|
|
220
220
|
/** The scanner's schemas say nothing about the currency; SaaS invoices come in several. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isDecidedField, isLocationValue, MAX_FILES, offeredSlot, shownFields, } from "@engenty-wizards/shared/definition";
|
|
2
|
-
import {
|
|
1
|
+
import { isDecidedField, isLang, isLocationValue, MAX_FILES, offeredSlot, shownFields, } from "@engenty-wizards/shared/definition";
|
|
2
|
+
import { note, saidText } from "@engenty-wizards/shared/run";
|
|
3
3
|
/** The field errors in a language, for whoever reads them. */
|
|
4
4
|
export function fieldErrorsIn(errors, lang) {
|
|
5
5
|
return errors.map((e) => ({ field: e.field, message: saidText(e.message, lang) }));
|
|
@@ -120,7 +120,7 @@ function readAudio(raw) {
|
|
|
120
120
|
if (typeof input.transcript === "string") {
|
|
121
121
|
out.transcript = input.transcript.slice(0, 20_000);
|
|
122
122
|
}
|
|
123
|
-
if (input.lang
|
|
123
|
+
if (isLang(input.lang)) {
|
|
124
124
|
out.lang = input.lang;
|
|
125
125
|
}
|
|
126
126
|
return out;
|
|
@@ -142,21 +142,21 @@ export function readPageInput(step, input, context = {}) {
|
|
|
142
142
|
continue;
|
|
143
143
|
}
|
|
144
144
|
if (field.required && empty(v) && field.kind !== "toggle") {
|
|
145
|
-
errors.push({ field: field.id, message:
|
|
145
|
+
errors.push({ field: field.id, message: note("fieldRequired") });
|
|
146
146
|
continue;
|
|
147
147
|
}
|
|
148
148
|
if (Array.isArray(v) && (field.kind === "image" || field.kind === "file")) {
|
|
149
149
|
if (field.min && v.length < field.min) {
|
|
150
150
|
errors.push({
|
|
151
151
|
field: field.id,
|
|
152
|
-
message:
|
|
152
|
+
message: note("chooseAtLeast", { min: field.min }),
|
|
153
153
|
});
|
|
154
154
|
continue;
|
|
155
155
|
}
|
|
156
156
|
if (field.max && v.length > field.max) {
|
|
157
157
|
errors.push({
|
|
158
158
|
field: field.id,
|
|
159
|
-
message:
|
|
159
|
+
message: note("chooseAtMost", { max: field.max }),
|
|
160
160
|
});
|
|
161
161
|
continue;
|
|
162
162
|
}
|
|
@@ -164,25 +164,25 @@ export function readPageInput(step, input, context = {}) {
|
|
|
164
164
|
if (field.kind === "number" && Number.isNaN(v)) {
|
|
165
165
|
errors.push({
|
|
166
166
|
field: field.id,
|
|
167
|
-
message:
|
|
167
|
+
message: note("enterNumber"),
|
|
168
168
|
});
|
|
169
169
|
continue;
|
|
170
170
|
}
|
|
171
171
|
if (field.kind === "select" && !empty(v) && !field.options?.includes(String(v))) {
|
|
172
|
-
errors.push({ field: field.id, message:
|
|
172
|
+
errors.push({ field: field.id, message: note("invalidChoice") });
|
|
173
173
|
continue;
|
|
174
174
|
}
|
|
175
175
|
if (field.kind === "slot" && !empty(v) && !field.options?.includes(String(v))) {
|
|
176
176
|
errors.push({
|
|
177
177
|
field: field.id,
|
|
178
|
-
message:
|
|
178
|
+
message: note("timeNotOffered"),
|
|
179
179
|
});
|
|
180
180
|
continue;
|
|
181
181
|
}
|
|
182
182
|
if (field.kind === "email" && !empty(v) && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(v))) {
|
|
183
183
|
errors.push({
|
|
184
184
|
field: field.id,
|
|
185
|
-
message:
|
|
185
|
+
message: note("notValidEmailAddress"),
|
|
186
186
|
});
|
|
187
187
|
continue;
|
|
188
188
|
}
|
|
@@ -193,7 +193,7 @@ export function readPageInput(step, input, context = {}) {
|
|
|
193
193
|
catch {
|
|
194
194
|
errors.push({
|
|
195
195
|
field: field.id,
|
|
196
|
-
message:
|
|
196
|
+
message: note("notValidUrl"),
|
|
197
197
|
});
|
|
198
198
|
continue;
|
|
199
199
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { conditionMatches, conditionsOf, isDecidedField, isDecisionStep, isOtherwise, MODEL_CLASSES, } from "@engenty-wizards/shared/definition";
|
|
2
2
|
import { closedChoicesFor, openValue, otherwiseIndex, unavoidableFrom, unavoidableSteps, } from "@engenty-wizards/shared/fit";
|
|
3
|
-
import {
|
|
3
|
+
import { note, saidText } from "@engenty-wizards/shared/run";
|
|
4
4
|
import { classProblem, filmClient } from "../models.js";
|
|
5
5
|
// The steps every run passes through, and the choices that lead around a missing model, are
|
|
6
6
|
// pure and shared (packages/shared/src/fit.ts): the standalone check uses the same.
|
|
@@ -273,13 +273,12 @@ export function blockingMessage(missing) {
|
|
|
273
273
|
if (!blocking.length) {
|
|
274
274
|
return null;
|
|
275
275
|
}
|
|
276
|
-
|
|
277
|
-
.map((m) => {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
})
|
|
281
|
-
.
|
|
282
|
-
return bilingual(line("de"), line("en"));
|
|
276
|
+
return blocking
|
|
277
|
+
.map((m) => note("blockedSteps", {
|
|
278
|
+
steps: m.steps.map((s) => note("quoted", { text: s.title })),
|
|
279
|
+
problem: m.problem,
|
|
280
|
+
}))
|
|
281
|
+
.reduce((first, second) => note("joined", { first, second }));
|
|
283
282
|
}
|
|
284
283
|
/** The class a marketplace capability stands for; the rest need no model of their own. */
|
|
285
284
|
const CAPABILITY_CLASS = {
|