@k2b/cloud 0.7.0 → 0.8.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/package.json +5 -4
- package/scripts/README.md +10 -0
- package/scripts/build.ts +6 -1
- package/scripts/preload.ts +7 -0
- package/scripts/sync-recovery-smoke.ts +21 -6
- package/src/_internal/build-metadata.ts +8 -1
- package/src/_internal/capabilities.ts +35 -12
- package/src/_internal/define-app.ts +28 -11
- package/src/_internal/page-responses.ts +1 -1
- package/src/_internal/readiness.ts +4 -1
- package/src/_internal/runtime-context.ts +1 -1
- package/src/access/PermissionEditor.tsx +15 -9
- package/src/access/PrincipalPicker.tsx +9 -3
- package/src/access/ResourceApiKeys.tsx +1 -1
- package/src/access/ui.ts +1 -2
- package/src/ai/admin.ts +2 -2
- package/src/ai/assistant-models.ts +1 -1
- package/src/ai/audio-tool.ts +1 -1
- package/src/ai/browser-code-contracts.ts +174 -52
- package/src/ai/browser.ts +4 -2
- package/src/ai/capabilities.ts +3 -3
- package/src/ai/chat/blocks.tsx +127 -50
- package/src/ai/chat/builtin-tools.tsx +2 -4
- package/src/ai/chat/capability-table.tsx +1 -1
- package/src/ai/chat/composer-adapter.ts +48 -13
- package/src/ai/chat/message-utils.ts +18 -5
- package/src/ai/chat/presentation.tsx +24 -11
- package/src/ai/chat/tool-disclosure.tsx +6 -2
- package/src/ai/chat/tool-groups.ts +8 -2
- package/src/ai/chat-quotas.ts +2 -2
- package/src/ai/chat-task-contracts.ts +9 -13
- package/src/ai/chat-tasks.ts +39 -18
- package/src/ai/client/controller.ts +87 -38
- package/src/ai/client/projection.ts +13 -6
- package/src/ai/client/transport.ts +4 -2
- package/src/ai/code-capability-routes.ts +22 -27
- package/src/ai/code-capability-transport.ts +2 -1
- package/src/ai/code-execution.ts +53 -0
- package/src/ai/code-mode-skill.ts +9 -5
- package/src/ai/code-runtime-tools.ts +16 -3
- package/src/ai/code-source-contracts.ts +100 -32
- package/src/ai/code-source-tools.ts +49 -6
- package/src/ai/compaction.ts +3 -3
- package/src/ai/default-tools.ts +87 -14
- package/src/ai/dictation-runtime.ts +1 -1
- package/src/ai/draft-content.ts +27 -12
- package/src/ai/enrich.ts +1 -1
- package/src/ai/executor.ts +8 -12
- package/src/ai/fetch-file-tool.ts +2 -2
- package/src/ai/file-content-version.ts +6 -1
- package/src/ai/file-tools.ts +8 -2
- package/src/ai/files-store.ts +55 -17
- package/src/ai/grids-skill.ts +2 -0
- package/src/ai/http.ts +18 -7
- package/src/ai/index.ts +24 -25
- package/src/ai/inference-calls.ts +3 -4
- package/src/ai/live.ts +1 -1
- package/src/ai/markdown-pdf-tool.ts +2 -2
- package/src/ai/memories.ts +30 -27
- package/src/ai/memory-learning-runs.ts +1 -1
- package/src/ai/memory-learning.ts +5 -5
- package/src/ai/memory-tool.ts +1 -5
- package/src/ai/memory-workflow-evidence.ts +9 -4
- package/src/ai/message-queue.ts +23 -12
- package/src/ai/migrate.ts +6 -4
- package/src/ai/model-pricing.ts +4 -4
- package/src/ai/pdf-render-worker.ts +3 -2
- package/src/ai/projects-routes.ts +15 -40
- package/src/ai/projects.ts +18 -13
- package/src/ai/quota-provider.ts +6 -5
- package/src/ai/quota-report.ts +5 -5
- package/src/ai/quotas.ts +3 -3
- package/src/ai/routes.ts +60 -34
- package/src/ai/run-timeout.ts +3 -1
- package/src/ai/runtime-tools.ts +6 -7
- package/src/ai/runtime.ts +38 -20
- package/src/ai/settings.ts +1 -1
- package/src/ai/short-id.ts +4 -5
- package/src/ai/skill-search.ts +21 -10
- package/src/ai/skill-seeds.ts +16 -7
- package/src/ai/skill-tool.ts +6 -1
- package/src/ai/skills-routes.ts +32 -15
- package/src/ai/skills.ts +54 -28
- package/src/ai/store.ts +80 -47
- package/src/ai/structured.ts +6 -2
- package/src/ai/system-prompt.ts +7 -5
- package/src/ai/task-contracts.ts +84 -0
- package/src/ai/task-execution.ts +92 -0
- package/src/ai/todo-contracts.ts +24 -12
- package/src/ai/todo-tool.ts +16 -13
- package/src/ai/tools.ts +1 -1
- package/src/ai/transcription.ts +4 -4
- package/src/ai/turn-timing.ts +1 -1
- package/src/ai/ui.tsx +2 -1
- package/src/ai/usage.ts +1 -1
- package/src/ai/vision-tool.ts +38 -17
- package/src/api/admin-ai-quotas.ts +14 -8
- package/src/api/admin-ai-skills.ts +3 -3
- package/src/api/admin-linux-identities.ts +10 -4
- package/src/api/admin-rail.ts +2 -2
- package/src/api/app-approval.ts +2 -2
- package/src/api/auth.ts +1 -1
- package/src/api/capabilities.ts +45 -13
- package/src/api/index.ts +5 -5
- package/src/api/mcp.ts +5 -12
- package/src/browser/CloudResourceSearch.tsx +1 -1
- package/src/browser/command-bridge.ts +1 -1
- package/src/browser/command-shortcuts.ts +1 -1
- package/src/browser/commands.ts +8 -7
- package/src/browser/testing.ts +2 -1
- package/src/capabilities/client.ts +1 -1
- package/src/capabilities/command-link.ts +1 -1
- package/src/capabilities/server.ts +2 -1
- package/src/cli/admin/ai-quotas.ts +5 -5
- package/src/cli/admin/app-credentials.ts +7 -9
- package/src/cli/admin/index.ts +3 -3
- package/src/cli/admin/instance.ts +2 -2
- package/src/cli/admin/linux.ts +4 -2
- package/src/cli/admin/sync.ts +1 -1
- package/src/cli/capabilities.ts +42 -29
- package/src/config/define-env.ts +97 -0
- package/src/config/env.ts +147 -54
- package/src/config/index.ts +3 -1
- package/src/contracts/capabilities.ts +8 -1
- package/src/contracts/index.ts +5 -7
- package/src/contracts/registry.ts +2 -0
- package/src/contracts/shared.ts +12 -3
- package/src/desktop/index.ts +1 -0
- package/src/desktop/solid.tsx +1 -1
- package/src/index.ts +8 -2
- package/src/server/index.ts +2 -2
- package/src/server/ratelimit.ts +1 -1
- package/src/server/services/access-revision.ts +3 -3
- package/src/server/services/access.ts +3 -1
- package/src/services/accounts/notification-sender.ts +12 -2
- package/src/services/announcements/index.ts +4 -4
- package/src/services/app-approval.ts +11 -10
- package/src/services/identity/key-config.ts +6 -4
- package/src/services/identity/runtime-config.ts +6 -5
- package/src/services/ipa/posix.ts +1 -1
- package/src/services/ipa/sync.ts +1 -1
- package/src/services/logging/index.ts +1 -1
- package/src/services/logging/trace.ts +1 -1
- package/src/services/mandates/index.ts +5 -2
- package/src/services/mandates/policy.ts +106 -6
- package/src/services/notifications/batches.ts +1 -0
- package/src/services/pdf/gotenberg.ts +50 -14
- package/src/services/pdf/index.ts +11 -11
- package/src/services/public-http.ts +1 -1
- package/src/services/rail-shortcuts.ts +1 -1
- package/src/services/rail-snapshot.ts +1 -1
- package/src/services/request-cache-redis.ts +2 -1
- package/src/services/session/user.ts +1 -1
- package/src/services/settings/app.ts +5 -1
- package/src/services/settings/core-settings.ts +6 -8
- package/src/services/settings/index.ts +3 -3
- package/src/services/settings/store.ts +3 -3
- package/src/services/webauthn.ts +1 -1
- package/src/shared/index.ts +3 -6
- package/src/shared/markdown/extensions/info-blocks.ts +1 -1
- package/src/ssr/AdminSidebar.tsx +2 -2
- package/src/ssr/AppLaunchpad.island.tsx +12 -2
- package/src/ssr/AppLaunchpadPanel.tsx +4 -4
- package/src/ssr/GlobalSearchDialog.tsx +6 -6
- package/src/ssr/GlobalSearchTrigger.island.tsx +2 -2
- package/src/ssr/Layout.tsx +2 -2
- package/src/ssr/LayoutHeader.tsx +1 -1
- package/src/ssr/LayoutHelp.tsx +4 -6
- package/src/ssr/LayoutHelpTrigger.island.tsx +2 -2
- package/src/ssr/MinimalLayout.tsx +1 -1
- package/src/ssr/MobileNavigation.tsx +2 -2
- package/src/ssr/ProfilePreferences.island.tsx +1 -1
- package/src/ssr/admin-navigation.ts +6 -2
- package/src/ssr/islands/index.ts +2 -2
- package/src/ssr/mobile-menu-history.ts +1 -1
- package/src/workflows/ai/index.ts +2 -2
- package/src/workflows/ai/runtime.ts +16 -91
- package/src/workflows/ai/store.ts +1 -1
- package/src/workflows/ai/types.ts +6 -82
- package/src/workflows/store/index.ts +2 -2
- package/src/server/services/freeipa/test-certificates.ts +0 -44
- package/src/services/session/test-fixture.ts +0 -18
package/src/ssr/LayoutHeader.tsx
CHANGED
|
@@ -4,8 +4,8 @@ import type { CloudTheme } from "../shared/theme";
|
|
|
4
4
|
import AppLaunchpad, { type AppLaunchpadApp } from "./AppLaunchpad.island";
|
|
5
5
|
import type { GlobalSearchHelpApp } from "./GlobalSearchHelpDialog";
|
|
6
6
|
import GlobalSearchTrigger from "./GlobalSearchTrigger.island";
|
|
7
|
-
import LayoutHelpTrigger from "./LayoutHelpTrigger.island";
|
|
8
7
|
import LayoutBreadcrumbs from "./LayoutBreadcrumbs.island";
|
|
8
|
+
import LayoutHelpTrigger from "./LayoutHelpTrigger.island";
|
|
9
9
|
import LayoutPreferences from "./LayoutPreferences.island";
|
|
10
10
|
import type { LayoutBreadcrumb } from "./layout-runtime";
|
|
11
11
|
import ProfilePreferences from "./ProfilePreferences.island";
|
package/src/ssr/LayoutHelp.tsx
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { searchHelpTopics } from "./layout-help-search";
|
|
1
|
+
import type { HelpDocumentManifest, HelpDocumentPayload, HelpSearchPayload } from "@k2b/cloud/shared";
|
|
3
2
|
import { clipboard } from "@k2b/stdlib/solid";
|
|
4
3
|
import { Button, IconButton, IconButtonLink, MarkdownView, NoticeCard, Placeholder, prompts, ScrollArea, useLocale } from "@k2b/ui";
|
|
5
|
-
import type { HelpDocumentManifest, HelpDocumentPayload, HelpSearchPayload } from "@k2b/cloud/shared";
|
|
6
4
|
import { createEffect, createMemo, createSignal, For, type JSX, onCleanup, onMount, Show } from "solid-js";
|
|
5
|
+
import { COMMANDS_CHANGED, contextCommandsWithShortcuts, shortcutLabel } from "../browser/command-shortcuts";
|
|
7
6
|
import { appAccentStyle } from "./app-appearance";
|
|
8
7
|
import { type GlobalSearchHelpApp, openGlobalSearchHelpDialog } from "./GlobalSearchHelpDialog";
|
|
9
8
|
import { helpMessages } from "./help-messages";
|
|
10
9
|
import { formatHelpBundleMarkdown, formatHelpDocumentMarkdown } from "./layout-help-markdown";
|
|
11
10
|
import { adjacentHelpDocuments, focusHelpArticleHeading, resetHelpArticleScroll } from "./layout-help-navigation";
|
|
11
|
+
import { searchHelpTopics } from "./layout-help-search";
|
|
12
12
|
import { layoutHelpTopicHref } from "./layout-help-url";
|
|
13
13
|
|
|
14
14
|
type HelpTopicBase = {
|
|
@@ -114,9 +114,7 @@ const Shortcuts = (props: { openSearchHelp: () => void }) => {
|
|
|
114
114
|
window.addEventListener(COMMANDS_CHANGED, update);
|
|
115
115
|
onCleanup(() => window.removeEventListener(COMMANDS_CHANGED, update));
|
|
116
116
|
});
|
|
117
|
-
const entries = createMemo(() =>
|
|
118
|
-
commands().filter((command) => command.shortcut),
|
|
119
|
-
);
|
|
117
|
+
const entries = createMemo(() => commands().filter((command) => command.shortcut));
|
|
120
118
|
return (
|
|
121
119
|
<div class="flex flex-col gap-3">
|
|
122
120
|
<p class="text-sm leading-relaxed text-dimmed">{t().shortcutsIntro}</p>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { registerContextAwareCommand } from "../browser/commands";
|
|
2
|
-
import { createEffect, onCleanup } from "solid-js";
|
|
3
1
|
import { IconButton, Tooltip, useLocale } from "@k2b/ui";
|
|
2
|
+
import { createEffect, onCleanup } from "solid-js";
|
|
3
|
+
import { registerContextAwareCommand } from "../browser/commands";
|
|
4
4
|
import type { GlobalSearchHelpApp } from "./GlobalSearchHelpDialog";
|
|
5
5
|
import { openLayoutHelpDialog } from "./LayoutHelp";
|
|
6
6
|
import { platformMessages } from "./platform-messages";
|
|
@@ -2,8 +2,8 @@ import { LocaleProvider } from "@k2b/ui";
|
|
|
2
2
|
import type { JSX } from "solid-js/jsx-runtime";
|
|
3
3
|
import { getLocale } from "../server/locale";
|
|
4
4
|
import { readThemeFromCookieHeader } from "../shared/theme";
|
|
5
|
-
import type { MinimalLayoutContext } from "./layout-context";
|
|
6
5
|
import LayoutPreferences from "./LayoutPreferences.island";
|
|
6
|
+
import type { MinimalLayoutContext } from "./layout-context";
|
|
7
7
|
import TimezoneCookie from "./TimezoneCookie.island";
|
|
8
8
|
|
|
9
9
|
export type MinimalLayoutPreferencePosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BottomSheet, Navigation, SegmentedControl, useLocale } from "@k2b/ui";
|
|
2
2
|
import { createSignal, onCleanup, Show } from "solid-js";
|
|
3
|
-
import {
|
|
3
|
+
import { type AppLaunchpadContext, AppLaunchpadPanel } from "./AppLaunchpadPanel";
|
|
4
4
|
import { openMobileMenu } from "./mobile-menu-history";
|
|
5
|
-
import { observeWorkspaceNavigation, readWorkspaceNavigation } from "./workspace-navigation";
|
|
6
5
|
import { platformMessages } from "./platform-messages";
|
|
6
|
+
import { observeWorkspaceNavigation, readWorkspaceNavigation } from "./workspace-navigation";
|
|
7
7
|
|
|
8
8
|
export function openCloudMobileMenu(apps: AppLaunchpadContext) {
|
|
9
9
|
return openMobileMenu((beforeSelect) => (close, context) => (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createProfileActions } from "./profile-actions";
|
|
2
1
|
import { Avatar, Dropdown } from "@k2b/ui";
|
|
3
2
|
import type { CloudTheme } from "../shared/theme";
|
|
3
|
+
import { createProfileActions } from "./profile-actions";
|
|
4
4
|
|
|
5
5
|
type ProfilePreferencesProps = {
|
|
6
6
|
avatarSrc?: string;
|
|
@@ -45,7 +45,9 @@ export const buildAdminGroups = (apps: readonly RuntimeContext["apps"][number][]
|
|
|
45
45
|
}))
|
|
46
46
|
.sort((a, b) => a.app.name.localeCompare(b.app.name));
|
|
47
47
|
|
|
48
|
-
aiLinks.push(
|
|
48
|
+
aiLinks.push(
|
|
49
|
+
...contributedApps.flatMap(({ groups }) => groups.filter((group) => group.section === "ai").flatMap((group) => group.links)),
|
|
50
|
+
);
|
|
49
51
|
|
|
50
52
|
const appsWithGroups = new Set(contributedApps.filter(({ groups }) => groups.length > 0).map(({ app }) => app.id));
|
|
51
53
|
const appLinks = apps
|
|
@@ -66,7 +68,9 @@ export const buildAdminGroups = (apps: readonly RuntimeContext["apps"][number][]
|
|
|
66
68
|
{ href: "/admin/announcements", icon: "ti-speakerphone", label: t.announcements },
|
|
67
69
|
],
|
|
68
70
|
},
|
|
69
|
-
...contributedApps.flatMap(({ groups }) =>
|
|
71
|
+
...contributedApps.flatMap(({ groups }) =>
|
|
72
|
+
groups.filter((group) => group.section !== "ai").map(({ label, links }) => ({ label, links })),
|
|
73
|
+
),
|
|
70
74
|
{
|
|
71
75
|
label: t.userManagement,
|
|
72
76
|
links: [
|
package/src/ssr/islands/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default as SearchBar } from "./SearchBar";
|
|
2
|
-
export { provideWorkspaceNavigation } from "../workspace-navigation";
|
|
3
1
|
export { default as WorkspaceNavigationProvider } from "../WorkspaceNavigationProvider";
|
|
2
|
+
export { provideWorkspaceNavigation } from "../workspace-navigation";
|
|
3
|
+
export { default as SearchBar } from "./SearchBar";
|
|
4
4
|
|
|
5
5
|
import { AppLaunchpadButton, AppLaunchpadProvider } from "../AppLaunchpad.island";
|
|
6
6
|
import { LayoutHelpDocuments, LayoutHelpPage } from "../LayoutHelp";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
export { startWorkflowAiRuntime, stopWorkflowAiRuntime, submitWorkflowAiTask, type WorkflowAiRuntimeOptions } from "./runtime";
|
|
1
2
|
export {
|
|
2
|
-
WORKFLOW_AI_DEPENDENCY_KIND,
|
|
3
3
|
createWorkflowAiTask,
|
|
4
4
|
getWorkflowAiTask,
|
|
5
5
|
getWorkflowAiTaskByEffectKey,
|
|
6
6
|
migrateWorkflowAi,
|
|
7
|
+
WORKFLOW_AI_DEPENDENCY_KIND,
|
|
7
8
|
wakeWorkflowAiTask,
|
|
8
9
|
workflowAiTaskExists,
|
|
9
10
|
} from "./store";
|
|
10
|
-
export { startWorkflowAiRuntime, stopWorkflowAiRuntime, submitWorkflowAiTask, type WorkflowAiRuntimeOptions } from "./runtime";
|
|
11
11
|
export {
|
|
12
12
|
type WorkflowAiRequest,
|
|
13
13
|
type WorkflowAiRequestInput,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { AiBackgroundAdmissionError, AiBackgroundCostError } from "../../ai/inference-calls";
|
|
2
1
|
import { StructuredOutputError } from "@k2b/nessi";
|
|
3
2
|
import type { Job, Worker } from "@k2b/sync";
|
|
4
|
-
import { z } from "zod";
|
|
5
3
|
import { lazySync } from "../../_internal/process-sync";
|
|
6
|
-
import { isAiSettingsError,
|
|
4
|
+
import { isAiSettingsError, runAiStructured } from "../../ai";
|
|
5
|
+
import { AiBackgroundAdmissionError, AiBackgroundCostError } from "../../ai/inference-calls";
|
|
6
|
+
import { executeAiTask } from "../../ai/task-execution";
|
|
7
7
|
|
|
8
|
-
import type { WorkflowJsonValue } from "../contracts";
|
|
9
8
|
import {
|
|
10
9
|
claimWorkflowAiTask,
|
|
11
10
|
completeWorkflowAiTask,
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
wakeWorkflowAiTask,
|
|
18
17
|
workflowAiTaskCancellationRequested,
|
|
19
18
|
} from "./store";
|
|
20
|
-
import type {
|
|
19
|
+
import type { WorkflowAiTask } from "./types";
|
|
21
20
|
|
|
22
21
|
const JOB_ID = "cloud.workflow-ai";
|
|
23
22
|
const MAX_ATTEMPTS = 3;
|
|
@@ -72,92 +71,18 @@ export const settleWorkflowAiAttemptFailure = async (
|
|
|
72
71
|
return "failed";
|
|
73
72
|
};
|
|
74
73
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
: field.type === "date_time"
|
|
88
|
-
? z.iso.datetime({ offset: true })
|
|
89
|
-
: choiceEnum(field.choices!);
|
|
90
|
-
if (!field.required) schema = schema.optional();
|
|
91
|
-
shape[field.name] = schema.describe(field.description);
|
|
92
|
-
}
|
|
93
|
-
return z.object(shape).strict();
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const executeWorkflowAiRequest = async (task: WorkflowAiTask, runStructured: StructuredRunner, signal: AbortSignal) => {
|
|
97
|
-
const request = task.request;
|
|
98
|
-
const common = {
|
|
99
|
-
appId: task.appId,
|
|
100
|
-
attribution: { workflowRunId: task.runId, stepKey: task.stepKey, userId: task.usageUserId },
|
|
101
|
-
requestedModelId: task.modelProfileId,
|
|
102
|
-
signal,
|
|
103
|
-
temperature: 0,
|
|
104
|
-
} satisfies Partial<RunAiStructuredInput<z.ZodType>>;
|
|
105
|
-
|
|
106
|
-
if (request.kind === "generate_text") {
|
|
107
|
-
const result = await runStructured({
|
|
108
|
-
...common,
|
|
109
|
-
task: "workflow-generate-text",
|
|
110
|
-
systemPrompt: request.prompt,
|
|
111
|
-
input: request.input === undefined ? "Create the requested text." : JSON.stringify(request.input),
|
|
112
|
-
outputName: "generated_text",
|
|
113
|
-
output: z.object({ text: z.string().max(request.maxOutputChars) }),
|
|
114
|
-
maxOutputTokens: Math.min(8_192, Math.max(64, Math.ceil(request.maxOutputChars / 2))),
|
|
115
|
-
});
|
|
116
|
-
return { output: result.output.text as WorkflowJsonValue, usage: result.usage ? asJson(result.usage) : null };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (request.kind === "classify") {
|
|
120
|
-
const result = await runStructured({
|
|
121
|
-
...common,
|
|
122
|
-
task: "workflow-classify",
|
|
123
|
-
systemPrompt: `${request.prompt}\nReturn exactly one of the declared choices.`,
|
|
124
|
-
input: JSON.stringify(request.input),
|
|
125
|
-
outputName: "classification",
|
|
126
|
-
output: z.object({ choice: choiceEnum(request.choices) }),
|
|
127
|
-
maxOutputTokens: 200,
|
|
128
|
-
});
|
|
129
|
-
return { output: result.output.choice as WorkflowJsonValue, usage: result.usage ? asJson(result.usage) : null };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (request.kind === "extract_data") {
|
|
133
|
-
const result = await runStructured({
|
|
134
|
-
...common,
|
|
135
|
-
task: "workflow-extract-data",
|
|
136
|
-
systemPrompt: `${request.prompt}\nReturn only the declared fields. Do not invent values that are not supported by the input.`,
|
|
137
|
-
input: JSON.stringify(request.input),
|
|
138
|
-
outputName: "structured_data",
|
|
139
|
-
output: structuredOutputSchema(request.fields),
|
|
140
|
-
maxOutputTokens: 4_096,
|
|
141
|
-
});
|
|
142
|
-
return { output: asJson(result.output), usage: result.usage ? asJson(result.usage) : null };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const maximum = request.maxChoices ?? request.choices.length;
|
|
146
|
-
const result = await runStructured({
|
|
147
|
-
...common,
|
|
148
|
-
task: "workflow-classify-many",
|
|
149
|
-
systemPrompt: `${request.prompt}\nReturn only unique values from the declared choices.`,
|
|
150
|
-
input: JSON.stringify(request.input),
|
|
151
|
-
outputName: "classifications",
|
|
152
|
-
output: z.object({ choices: z.array(choiceEnum(request.choices)).min(request.minChoices).max(maximum) }),
|
|
153
|
-
maxOutputTokens: 500,
|
|
154
|
-
});
|
|
155
|
-
const selected = new Set(result.output.choices);
|
|
156
|
-
return {
|
|
157
|
-
output: request.choices.filter((choice) => selected.has(choice)) as WorkflowJsonValue,
|
|
158
|
-
usage: result.usage ? asJson(result.usage) : null,
|
|
159
|
-
};
|
|
160
|
-
};
|
|
74
|
+
export const executeWorkflowAiRequest = async (task: WorkflowAiTask, runStructured: StructuredRunner, signal: AbortSignal) =>
|
|
75
|
+
executeAiTask(
|
|
76
|
+
task.request,
|
|
77
|
+
{
|
|
78
|
+
appId: task.appId,
|
|
79
|
+
attribution: { workflowRunId: task.runId, stepKey: task.stepKey, userId: task.usageUserId },
|
|
80
|
+
requestedModelId: task.modelProfileId,
|
|
81
|
+
signal,
|
|
82
|
+
taskPrefix: "workflow",
|
|
83
|
+
},
|
|
84
|
+
runStructured,
|
|
85
|
+
);
|
|
161
86
|
|
|
162
87
|
const retryableError = (error: unknown): boolean => {
|
|
163
88
|
if (error instanceof AiBackgroundAdmissionError) return error.retryable;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { notifyWorkflowWorker } from "../store/worker-runtime";
|
|
2
1
|
import { type SQL, sql } from "bun";
|
|
3
2
|
import type { WorkflowJsonValue } from "../contracts";
|
|
4
3
|
import { wakeWorkflowRunsWaitingOn } from "../store/runs";
|
|
4
|
+
import { notifyWorkflowWorker } from "../store/worker-runtime";
|
|
5
5
|
import {
|
|
6
6
|
type WorkflowAiRequest,
|
|
7
7
|
type WorkflowAiRequestInput,
|
|
@@ -1,88 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AiTaskRequest as WorkflowAiRequest } from "../../ai/task-contracts";
|
|
2
2
|
import type { WorkflowJsonValue } from "../contracts";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.min(2)
|
|
10
|
-
.max(50)
|
|
11
|
-
.refine((values) => new Set(values).size === values.length, "Choices must be unique.");
|
|
4
|
+
export {
|
|
5
|
+
type AiTaskRequest as WorkflowAiRequest,
|
|
6
|
+
type AiTaskRequestInput as WorkflowAiRequestInput,
|
|
7
|
+
AiTaskRequestSchema as workflowAiRequestSchema,
|
|
8
|
+
} from "../../ai/task-contracts";
|
|
12
9
|
|
|
13
|
-
const structuredField = z
|
|
14
|
-
.object({
|
|
15
|
-
name: z
|
|
16
|
-
.string()
|
|
17
|
-
.trim()
|
|
18
|
-
.regex(/^[A-Za-z][A-Za-z0-9_]{0,79}$/),
|
|
19
|
-
type: z.enum(["text", "number", "boolean", "date_time", "enum"]),
|
|
20
|
-
description: z.string().trim().min(1).max(500),
|
|
21
|
-
required: z.boolean().default(true),
|
|
22
|
-
choices: z.array(choice).min(1).max(50).optional(),
|
|
23
|
-
maxLength: z.number().int().min(1).max(20_000).optional(),
|
|
24
|
-
})
|
|
25
|
-
.strict()
|
|
26
|
-
.superRefine((field, ctx) => {
|
|
27
|
-
if (field.type === "enum" && !field.choices)
|
|
28
|
-
ctx.addIssue({ code: "custom", path: ["choices"], message: "Enum fields require choices." });
|
|
29
|
-
if (field.type !== "enum" && field.choices)
|
|
30
|
-
ctx.addIssue({ code: "custom", path: ["choices"], message: "Choices are only valid for enum fields." });
|
|
31
|
-
if (field.type !== "text" && field.maxLength)
|
|
32
|
-
ctx.addIssue({ code: "custom", path: ["maxLength"], message: "maxLength is only valid for text fields." });
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const structuredFields = z
|
|
36
|
-
.array(structuredField)
|
|
37
|
-
.min(1)
|
|
38
|
-
.max(40)
|
|
39
|
-
.refine((fields) => new Set(fields.map((field) => field.name)).size === fields.length, "Structured field names must be unique.");
|
|
40
|
-
|
|
41
|
-
export const workflowAiRequestSchema = z.discriminatedUnion("kind", [
|
|
42
|
-
z.object({
|
|
43
|
-
kind: z.literal("generate_text"),
|
|
44
|
-
prompt,
|
|
45
|
-
input: z.unknown().optional(),
|
|
46
|
-
modelProfileId,
|
|
47
|
-
maxOutputChars: z.number().int().min(1).max(20_000).default(4_000),
|
|
48
|
-
}),
|
|
49
|
-
z.object({
|
|
50
|
-
kind: z.literal("classify"),
|
|
51
|
-
prompt,
|
|
52
|
-
input: z.unknown(),
|
|
53
|
-
choices,
|
|
54
|
-
modelProfileId,
|
|
55
|
-
}),
|
|
56
|
-
z
|
|
57
|
-
.object({
|
|
58
|
-
kind: z.literal("classify_many"),
|
|
59
|
-
prompt,
|
|
60
|
-
input: z.unknown(),
|
|
61
|
-
choices,
|
|
62
|
-
minChoices: z.number().int().min(0).max(50).default(0),
|
|
63
|
-
maxChoices: z.number().int().min(0).max(50).optional(),
|
|
64
|
-
modelProfileId,
|
|
65
|
-
})
|
|
66
|
-
.superRefine((value, ctx) => {
|
|
67
|
-
const maximum = value.maxChoices ?? value.choices.length;
|
|
68
|
-
if (maximum > value.choices.length) {
|
|
69
|
-
ctx.addIssue({ code: "custom", path: ["maxChoices"], message: "maxChoices cannot exceed the number of choices." });
|
|
70
|
-
}
|
|
71
|
-
if (value.minChoices > maximum) {
|
|
72
|
-
ctx.addIssue({ code: "custom", path: ["minChoices"], message: "minChoices cannot exceed maxChoices." });
|
|
73
|
-
}
|
|
74
|
-
}),
|
|
75
|
-
z.object({
|
|
76
|
-
kind: z.literal("extract_data"),
|
|
77
|
-
prompt,
|
|
78
|
-
input: z.unknown(),
|
|
79
|
-
fields: structuredFields,
|
|
80
|
-
modelProfileId,
|
|
81
|
-
}),
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
export type WorkflowAiRequest = z.infer<typeof workflowAiRequestSchema>;
|
|
85
|
-
export type WorkflowAiRequestInput = z.input<typeof workflowAiRequestSchema>;
|
|
86
10
|
export type WorkflowAiTaskStatus = "queued" | "running" | "succeeded" | "failed" | "canceled";
|
|
87
11
|
|
|
88
12
|
export type WorkflowAiTask = {
|
|
@@ -50,11 +50,11 @@ export {
|
|
|
50
50
|
} from "./events";
|
|
51
51
|
export {
|
|
52
52
|
getWorkflowRun,
|
|
53
|
-
listWorkflowFamilies,
|
|
54
|
-
listWorkflowRunTimeline,
|
|
55
53
|
listStrandedWorkflowEffects,
|
|
54
|
+
listWorkflowFamilies,
|
|
56
55
|
listWorkflowRunSteps,
|
|
57
56
|
listWorkflowRuns,
|
|
57
|
+
listWorkflowRunTimeline,
|
|
58
58
|
type StrandedWorkflowEffect,
|
|
59
59
|
type WorkflowAppHealth,
|
|
60
60
|
type WorkflowFamilyFilter,
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export const TEST_CA_CERT = `-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIBljCCATugAwIBAgIUaD/zikxyQaxGreCVzb9YufuusxIwCgYIKoZIzj0EAwIw
|
|
3
|
-
IDEeMBwGA1UEAwwVQ2xvdWQgRnJlZUlQQSBUZXN0IENBMB4XDTI2MDcyOTE1NTgx
|
|
4
|
-
MFoXDTM2MDcyNjE1NTgxMFowIDEeMBwGA1UEAwwVQ2xvdWQgRnJlZUlQQSBUZXN0
|
|
5
|
-
IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYZ7eU7/C71ilbpKa9k/FXObw
|
|
6
|
-
Vq4u/3rtpW/kSjsJaIVNPFp5oFBdHceL0UPgoxwpaJiJNHiwQHF/BBxaJ7HOAKNT
|
|
7
|
-
MFEwHQYDVR0OBBYEFOflw/p5xNlS0am+HytNLyXVEUndMB8GA1UdIwQYMBaAFOfl
|
|
8
|
-
w/p5xNlS0am+HytNLyXVEUndMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID
|
|
9
|
-
SQAwRgIhAJmRoNV5dxKvNOd2KoytvK/6ckRWN+Uu0ljc5y/g4izqAiEAsLCjxWvz
|
|
10
|
-
mgt1Z3uk+QkT9D1vHCuKSvcqv3aVn0DClxA=
|
|
11
|
-
-----END CERTIFICATE-----`;
|
|
12
|
-
|
|
13
|
-
export const TEST_SERVER_CERT = `-----BEGIN CERTIFICATE-----
|
|
14
|
-
MIIBpDCCAUmgAwIBAgIUNGe5IovnDTTKxjxwHBGVcnOaXaQwCgYIKoZIzj0EAwIw
|
|
15
|
-
IDEeMBwGA1UEAwwVQ2xvdWQgRnJlZUlQQSBUZXN0IENBMB4XDTI2MDcyOTE1NTgx
|
|
16
|
-
MFoXDTM2MDcyNjE1NTgxMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZI
|
|
17
|
-
zj0CAQYIKoZIzj0DAQcDQgAEolKc1EyyTH6MKX0GR7FhbXCN0O3G/D2riPJ045K+
|
|
18
|
-
qCL6m0Fso38eNxKbNENSkE1tX7j4uv6tcLmtHU/cKxjUg6NtMGswFAYDVR0RBA0w
|
|
19
|
-
C4IJbG9jYWxob3N0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBT/iu3f
|
|
20
|
-
aYfd6r4xoPTkZujj/0rwWjAfBgNVHSMEGDAWgBTn5cP6ecTZUtGpvh8rTS8l1RFJ
|
|
21
|
-
3TAKBggqhkjOPQQDAgNJADBGAiEAgsXqgbBm2RJaUZIs0IR2rbI+6S+1CtugVMHl
|
|
22
|
-
oxuRagcCIQCtoMZh0rZFlmUkH19BxrDvQe3JqCuQpd2HiZdvZTJhyQ==
|
|
23
|
-
-----END CERTIFICATE-----`;
|
|
24
|
-
|
|
25
|
-
export const TEST_SERVER_KEY = `-----BEGIN EC PARAMETERS-----
|
|
26
|
-
BggqhkjOPQMBBw==
|
|
27
|
-
-----END EC PARAMETERS-----
|
|
28
|
-
-----BEGIN EC PRIVATE KEY-----
|
|
29
|
-
MHcCAQEEIKFSLmqZO5KgG9hGbNhhJa0V2IMl39N2UHUj5VUh6DsmoAoGCCqGSM49
|
|
30
|
-
AwEHoUQDQgAEolKc1EyyTH6MKX0GR7FhbXCN0O3G/D2riPJ045K+qCL6m0Fso38e
|
|
31
|
-
NxKbNENSkE1tX7j4uv6tcLmtHU/cKxjUgw==
|
|
32
|
-
-----END EC PRIVATE KEY-----`;
|
|
33
|
-
|
|
34
|
-
export const TEST_WRONG_CA_CERT = `-----BEGIN CERTIFICATE-----
|
|
35
|
-
MIIBhDCCASugAwIBAgIUWM3XX235lciHJ/UKoajhrSx2dPwwCgYIKoZIzj0EAwIw
|
|
36
|
-
GDEWMBQGA1UEAwwNV3JvbmcgVGVzdCBDQTAeFw0yNjA3MjkxNTU4MTBaFw0zNjA3
|
|
37
|
-
MjYxNTU4MTBaMBgxFjAUBgNVBAMMDVdyb25nIFRlc3QgQ0EwWTATBgcqhkjOPQIB
|
|
38
|
-
BggqhkjOPQMBBwNCAAREOwLQCQYQI7zEa7GaSZag98eOF5KMckBPrDsDxS0Bb5lx
|
|
39
|
-
uIa3iWu9CI6Xkw+v+avpPF+Oz3QB7GXgCboKHFico1MwUTAdBgNVHQ4EFgQU1PRs
|
|
40
|
-
qLXtaHVxaKu0e0le1KpD6GYwHwYDVR0jBBgwFoAU1PRsqLXtaHVxaKu0e0le1KpD
|
|
41
|
-
6GYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiA9vA9jI66Un7zQ
|
|
42
|
-
ycf0+6Ze0y5aSM9FLojGcVuzZb0iyAIgIC6ooFag9BuAZqcj/k07hjARi6UVOpEy
|
|
43
|
-
sIJIkokji38=
|
|
44
|
-
-----END CERTIFICATE-----`;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Hono } from "hono";
|
|
2
|
-
import { sql } from "bun";
|
|
3
|
-
import { session } from "./index";
|
|
4
|
-
|
|
5
|
-
/** Integration fixture: run with an isolated Core authority and its public JWKS endpoint. */
|
|
6
|
-
export const createTestSession = async (userId: string): Promise<string> => {
|
|
7
|
-
// Most session fixtures represent established users, not first-use onboarding.
|
|
8
|
-
await sql`INSERT INTO auth.legal_acceptances (user_id, session_id, document_version, documents)
|
|
9
|
-
VALUES (${userId}::uuid, ${crypto.randomUUID()}::uuid, 'test-fixture', '[]'::jsonb) ON CONFLICT DO NOTHING`;
|
|
10
|
-
const app = new Hono().post("/login", async (c) => c.json({ token: await session.create(c, userId) }));
|
|
11
|
-
const response = await app.request("/login", { method: "POST" });
|
|
12
|
-
if (response.status !== 200) throw new Error(`Session fixture login failed: ${response.status}`);
|
|
13
|
-
const body: unknown = await response.json();
|
|
14
|
-
if (!body || typeof body !== "object" || !("token" in body) || typeof body.token !== "string") {
|
|
15
|
-
throw new Error("Session fixture did not return a token");
|
|
16
|
-
}
|
|
17
|
-
return body.token;
|
|
18
|
-
};
|