@k2b/cloud 0.6.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/README.md +2 -2
- package/package.json +22 -11
- package/scripts/README.md +10 -0
- package/scripts/browser-performance.ts +14 -0
- package/scripts/build-pdf-renderer.ts +39 -0
- package/scripts/build.ts +20 -35
- package/scripts/preload.ts +16 -12
- package/scripts/sync-recovery-smoke.ts +22 -6
- package/src/_internal/app-presentation.ts +14 -2
- package/src/_internal/build-metadata.ts +8 -1
- package/src/_internal/capabilities.ts +131 -7
- package/src/_internal/capability-streams.ts +81 -0
- package/src/_internal/define-app.ts +80 -37
- package/src/_internal/heartbeat.ts +4 -0
- package/src/_internal/help-catalog.ts +27 -172
- package/src/_internal/help.ts +13 -76
- package/src/_internal/page-responses.ts +2 -0
- package/src/_internal/postgres-application-name.ts +30 -0
- package/src/_internal/process-identity.ts +15 -0
- package/src/_internal/process-sync.ts +1 -1
- package/src/_internal/readiness.ts +4 -1
- package/src/_internal/registry-validation.ts +29 -25
- package/src/_internal/registry.ts +2 -53
- package/src/_internal/runtime-context.ts +5 -16
- package/src/_internal/server-timing.ts +13 -0
- package/src/_internal/status-preserving-ssr.ts +18 -6
- package/src/_internal/web-vitals-asset.ts +10 -0
- package/src/access/PermissionEditor.tsx +18 -151
- package/src/access/PrincipalPicker.tsx +110 -0
- package/src/access/ResourceApiKeys.tsx +1 -1
- package/src/access/ui.ts +1 -0
- package/src/ai/admin.ts +14 -13
- package/src/ai/assistant-models.ts +12 -1
- package/src/ai/audio-format.ts +34 -0
- package/src/ai/audio-tool.ts +90 -0
- package/src/ai/browser-code-contracts.ts +201 -0
- package/src/ai/browser.ts +4 -0
- package/src/ai/capabilities.ts +55 -36
- package/src/ai/capability-execution.ts +47 -12
- package/src/ai/chat/blocks.tsx +229 -90
- package/src/ai/chat/builtin-tools.tsx +2 -4
- package/src/ai/chat/capability-result.ts +15 -0
- package/src/ai/chat/capability-table.tsx +2 -10
- package/src/ai/chat/composer-adapter.ts +83 -3
- package/src/ai/chat/message-actions.tsx +8 -7
- package/src/ai/chat/message-utils.ts +25 -1
- package/src/ai/chat/messages.ts +2 -0
- package/src/ai/chat/presentation.tsx +31 -47
- package/src/ai/chat/primitives.tsx +43 -1
- package/src/ai/chat/tool-disclosure.tsx +21 -2
- package/src/ai/chat/tool-groups.ts +58 -0
- package/src/ai/chat-quotas.ts +25 -0
- package/src/ai/chat-task-contracts.ts +14 -10
- package/src/ai/chat-tasks.ts +297 -43
- package/src/ai/client/controller.ts +165 -39
- package/src/ai/client/file-source.ts +12 -6
- package/src/ai/client/live-connection.ts +1 -0
- package/src/ai/client/projection.ts +29 -11
- package/src/ai/client/transport.ts +6 -0
- package/src/ai/code-capability-routes.ts +105 -0
- package/src/ai/code-capability-transport.ts +39 -0
- package/src/ai/code-execution.ts +53 -0
- package/src/ai/code-mode-skill.ts +118 -0
- package/src/ai/code-runtime-tools.ts +179 -0
- package/src/ai/code-source-contracts.ts +270 -0
- package/src/ai/code-source-tools.ts +188 -0
- package/src/ai/compaction.ts +27 -6
- package/src/ai/data-analysis-skill.ts +10 -0
- package/src/ai/default-tools.ts +99 -3
- package/src/ai/dictation-runtime.ts +171 -0
- package/src/ai/dictations.ts +188 -0
- package/src/ai/draft-content.ts +49 -0
- package/src/ai/enrich.ts +6 -0
- package/src/ai/executor.ts +189 -33
- package/src/ai/fetch-file-tool.ts +2 -2
- package/src/ai/file-content-version.ts +27 -0
- package/src/ai/file-context.ts +2 -1
- package/src/ai/file-media-type.ts +12 -0
- package/src/ai/file-reference-contracts.ts +15 -0
- package/src/ai/file-tools.ts +8 -1
- package/src/ai/files-store.ts +212 -71
- package/src/ai/fixtures/vision-encrypted.pdf +0 -0
- package/src/ai/grids-skill.ts +42 -10
- package/src/ai/http.ts +26 -8
- package/src/ai/index.ts +26 -3
- package/src/ai/inference-calls.ts +197 -0
- package/src/ai/live-events.ts +5 -1
- 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 +64 -32
- package/src/ai/memory-tool.ts +1 -5
- package/src/ai/memory-workflow-evidence.ts +9 -4
- package/src/ai/message-queue.ts +178 -0
- package/src/ai/migrate.ts +189 -11
- package/src/ai/model-pricing.ts +43 -0
- package/src/ai/pdf-render-worker.ts +75 -0
- package/src/ai/pdf-render.fixture.ts +28 -0
- package/src/ai/pdf-render.ts +77 -0
- package/src/ai/projects-routes.ts +18 -43
- package/src/ai/projects.ts +33 -14
- package/src/ai/protocol.ts +3 -0
- package/src/ai/provider.ts +1 -8
- package/src/ai/quota-provider.ts +192 -0
- package/src/ai/quota-report.ts +152 -0
- package/src/ai/quotas-migrate.ts +45 -0
- package/src/ai/quotas.ts +168 -0
- package/src/ai/routes.ts +241 -11
- package/src/ai/run-timeout.ts +12 -0
- package/src/ai/runtime-tools.ts +7 -5
- package/src/ai/runtime.ts +74 -17
- package/src/ai/settings.ts +36 -8
- package/src/ai/short-id.ts +4 -5
- package/src/ai/skill-catalog.ts +0 -10
- package/src/ai/skill-search.ts +58 -0
- package/src/ai/skill-seeds.ts +114 -20
- package/src/ai/skill-tool.ts +21 -5
- package/src/ai/skills-routes.ts +49 -4
- package/src/ai/skills.ts +358 -163
- package/src/ai/store.ts +416 -201
- package/src/ai/stream.ts +5 -0
- package/src/ai/structured-runs.ts +4 -3
- package/src/ai/structured.ts +12 -1
- package/src/ai/system-prompt.ts +14 -2
- package/src/ai/task-contracts.ts +84 -0
- package/src/ai/task-execution.ts +92 -0
- package/src/ai/timeline.ts +2 -5
- package/src/ai/todo-contracts.ts +32 -0
- package/src/ai/todo-tool.ts +19 -0
- package/src/ai/tool-audit.ts +30 -40
- package/src/ai/tools.ts +6 -0
- package/src/ai/transcription.ts +202 -0
- package/src/ai/turn-timing.ts +114 -0
- package/src/ai/types.ts +58 -10
- package/src/ai/ui.tsx +3 -0
- package/src/ai/usage.ts +118 -118
- package/src/ai/vision-tool.ts +60 -10
- package/src/api/admin-ai-projects.ts +2 -2
- package/src/api/admin-ai-quotas.ts +80 -0
- package/src/api/admin-ai-skills.ts +48 -5
- package/src/api/admin-ai-usage.ts +2 -2
- package/src/api/admin-core-settings.ts +25 -0
- package/src/api/admin-identity.ts +91 -51
- package/src/api/admin-linux-identities.ts +10 -4
- package/src/api/admin-rail.ts +58 -0
- package/src/api/announcements.ts +14 -0
- package/src/api/app-approval.ts +2 -2
- package/src/api/auth.ts +1 -1
- package/src/api/capabilities.ts +324 -43
- package/src/api/capability-streams.ts +262 -0
- package/src/api/help.ts +8 -44
- package/src/api/index.ts +8 -2
- package/src/api/mcp.ts +45 -34
- package/src/api/me-web-vitals.ts +35 -0
- package/src/api/me.ts +2 -0
- package/src/api/search/schemas.ts +26 -15
- package/src/api/search.bench.ts +1 -1
- package/src/api/search.ts +54 -17
- package/src/browser/CloudResourceSearch.tsx +640 -702
- package/src/browser/app-approval-vault.ts +19 -7
- package/src/browser/command-bridge.ts +109 -0
- package/src/browser/command-shortcuts.ts +76 -0
- package/src/browser/commands.ts +67 -0
- package/src/browser/navigation-search.ts +48 -0
- package/src/browser/notifications.ts +1 -1
- package/src/browser/resource-picker.tsx +5 -18
- package/src/browser/resource-search-dialog.ts +9 -0
- package/src/browser/resource-search-input.ts +46 -0
- package/src/browser/resource-search-messages.ts +76 -40
- package/src/browser/resource-search.ts +7 -0
- package/src/browser/search-bridge.ts +102 -0
- package/src/browser/search-commands.ts +59 -0
- package/src/browser/search.ts +13 -0
- package/src/browser/spotlight-position.ts +208 -0
- package/src/browser/testing.ts +6 -0
- package/src/browser/web-vitals.ts +25 -0
- package/src/capabilities/claims.ts +179 -0
- package/src/capabilities/client.ts +34 -0
- package/src/capabilities/command-link.ts +16 -0
- package/src/capabilities/executions.ts +298 -0
- package/src/capabilities/migrate.ts +81 -0
- package/src/capabilities/server.ts +116 -35
- package/src/capabilities/stream-body.ts +16 -0
- package/src/capabilities/streams.ts +28 -0
- package/src/cli/admin/ai-quotas.ts +161 -0
- package/src/cli/admin/ai-skills.ts +64 -0
- package/src/cli/admin/ai-usage.ts +53 -30
- package/src/cli/admin/app-credentials.ts +77 -0
- package/src/cli/admin/data.ts +17 -0
- package/src/cli/admin/index.ts +10 -1
- 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 -0
- package/src/cli/capability-streams.ts +25 -0
- package/src/cli/index.ts +3 -2
- package/src/config/define-env.ts +97 -0
- package/src/config/env.ts +147 -51
- package/src/config/index.ts +3 -1
- package/src/contracts/app.ts +23 -3
- package/src/contracts/capabilities.ts +75 -5
- package/src/contracts/capability-streams.ts +46 -0
- package/src/contracts/commands.ts +49 -0
- package/src/contracts/index.ts +5 -2
- package/src/contracts/rail-admin.ts +38 -0
- package/src/contracts/rail-preferences.ts +16 -0
- package/src/contracts/registry.ts +5 -27
- package/src/contracts/settings-types.ts +1 -1
- package/src/contracts/shared.ts +18 -5
- package/src/contracts/web-vitals.ts +27 -0
- package/src/desktop/index.ts +1 -0
- package/src/desktop/solid.tsx +1 -1
- package/src/index.ts +8 -6
- package/src/server/index.ts +3 -0
- package/src/server/middleware/auth.ts +3 -2
- package/src/server/middleware/route-template.ts +9 -3
- package/src/server/middleware/runtime.ts +2 -1
- package/src/server/middleware/settings.ts +17 -11
- package/src/server/ratelimit.ts +1 -1
- package/src/server/services/access-revision.ts +10 -0
- package/src/server/services/access.ts +3 -1
- package/src/server/services/index.ts +1 -0
- package/src/services/account-category-policy.ts +9 -0
- package/src/services/account-lifecycle/audit.ts +1 -1
- package/src/services/accounts/app.ts +12 -2
- package/src/services/accounts/email-write.ts +23 -0
- package/src/services/accounts/groups.ts +15 -4
- package/src/services/accounts/identities.ts +249 -0
- package/src/services/accounts/identity-reconciliation.ts +87 -0
- package/src/services/accounts/ipa-data.ts +2 -2
- package/src/services/accounts/local-groups.ts +2 -2
- package/src/services/accounts/notification-sender.ts +12 -2
- package/src/services/accounts/posix.ts +45 -29
- package/src/services/accounts/users.ts +2 -2
- package/src/services/announcements/index.ts +69 -8
- package/src/services/app-approval.ts +11 -10
- package/src/services/audit/index.ts +1 -1
- package/src/services/cache-fill.ts +35 -0
- package/src/services/help/index.ts +109 -0
- package/src/services/help/maintenance.ts +25 -0
- package/src/services/help/store.ts +180 -0
- package/src/services/help/types.ts +46 -0
- package/src/services/identity/invocation-actor.ts +2 -2
- package/src/services/identity/key-config.ts +8 -5
- package/src/services/identity/key-ring.ts +1 -1
- package/src/services/identity/runtime-config.ts +6 -5
- package/src/services/index.ts +15 -0
- package/src/services/ipa/posix.ts +1 -1
- package/src/services/ipa/sync.ts +1 -1
- package/src/services/ipa/users.ts +268 -221
- package/src/services/legal-consent.ts +1 -1
- package/src/services/logging/index.ts +15 -13
- package/src/services/logging/trace.ts +2 -1
- package/src/services/logging/web-vitals.ts +81 -0
- package/src/services/mandates/index.ts +21 -4
- package/src/services/mandates/policy.ts +165 -2
- package/src/services/notifications/batches.ts +125 -57
- package/src/services/notifications/browser.ts +12 -0
- package/src/services/notifications/index.ts +0 -2
- package/src/services/notifications/platform.ts +0 -4
- package/src/services/oauth-tokens.ts +3 -3
- package/src/services/pdf/gotenberg.ts +131 -72
- package/src/services/pdf/index.ts +11 -8
- package/src/services/providers/local/users.ts +25 -16
- package/src/services/public-http.ts +101 -0
- package/src/services/rail-shortcuts.ts +95 -0
- package/src/services/rail-snapshot.ts +53 -0
- package/src/services/request-cache-redis.ts +29 -0
- package/src/services/session/index.ts +15 -2
- package/src/services/session/user.ts +62 -37
- package/src/services/settings/app.ts +5 -1
- package/src/services/settings/core-settings.ts +26 -35
- package/src/services/settings/defaults.ts +5 -0
- package/src/services/settings/index.ts +3 -3
- package/src/services/settings/store.ts +58 -84
- package/src/services/webauthn.ts +1 -1
- package/src/shared/ai-costs.ts +42 -0
- package/src/shared/ai-platform-prompt.ts +1 -1
- package/src/shared/ai-quotas.ts +136 -0
- package/src/shared/ai-usage.ts +6 -16
- package/src/shared/app-presentation.ts +21 -15
- package/src/shared/capability-messages.ts +14 -0
- package/src/shared/help.ts +6 -42
- package/src/shared/index.ts +3 -0
- package/src/shared/markdown/extensions/info-blocks.ts +1 -1
- package/src/ssr/AdminLayout.tsx +7 -5
- package/src/ssr/AdminSidebar.tsx +30 -16
- package/src/ssr/AppLaunchpad.island.tsx +33 -136
- package/src/ssr/AppLaunchpadPanel.tsx +181 -0
- package/src/ssr/BrowserPushRegistration.island.tsx +12 -0
- package/src/ssr/GlobalSearchDialog.tsx +167 -20
- package/src/ssr/GlobalSearchTrigger.island.tsx +33 -22
- package/src/ssr/Layout.tsx +17 -6
- package/src/ssr/LayoutBreadcrumbs.island.tsx +3 -5
- package/src/ssr/LayoutFooter.tsx +1 -1
- package/src/ssr/LayoutHeader.tsx +46 -14
- package/src/ssr/LayoutHelp.tsx +22 -23
- package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
- package/src/ssr/LayoutRail.tsx +17 -9
- package/src/ssr/MinimalLayout.tsx +1 -1
- package/src/ssr/MobileNavigation.tsx +71 -0
- package/src/ssr/MobileProfileActions.tsx +49 -0
- package/src/ssr/ProfilePreferences.island.tsx +3 -36
- package/src/ssr/RailApps.island.tsx +2 -2
- package/src/ssr/RailEditor.tsx +17 -2
- package/src/ssr/WorkspaceNavigation.island.tsx +7 -0
- package/src/ssr/WorkspaceNavigationProvider.tsx +16 -0
- package/src/ssr/admin-navigation.ts +11 -1
- package/src/ssr/help.ts +29 -0
- package/src/ssr/islands/SearchBar.tsx +67 -0
- package/src/ssr/islands/index.ts +3 -1
- package/src/ssr/layout-context.ts +2 -2
- package/src/ssr/layout-help-search.ts +15 -0
- package/src/ssr/mobile-menu-history.ts +70 -0
- package/src/ssr/platform-messages.ts +16 -8
- package/src/ssr/profile-actions.ts +42 -0
- package/src/ssr/rail-context.ts +8 -4
- package/src/ssr/rail-messages.ts +2 -0
- package/src/ssr/rail-navigation.ts +3 -3
- package/src/ssr/workspace-navigation.ts +75 -0
- package/src/styles/effects.css +6 -6
- package/src/styles/global.css +54 -0
- package/src/styles/input.css +43 -41
- package/src/styles/resource-search.css +505 -0
- package/src/styles/utilities-feedback.css +13 -0
- package/src/styles/utilities-layout.css +1 -5
- package/src/styles/utilities-navigation.css +3 -39
- package/src/types/ambient.d.ts +5 -0
- package/src/workflows/ai/index.ts +2 -2
- package/src/workflows/ai/runtime.ts +19 -90
- package/src/workflows/ai/store.ts +2 -0
- package/src/workflows/ai/types.ts +6 -82
- package/src/workflows/ai-actions.ts +16 -13
- package/src/workflows/definition.ts +10 -5
- package/src/workflows/store/actions.ts +44 -20
- package/src/workflows/store/index.ts +4 -2
- package/src/workflows/store/runs.ts +36 -0
- package/src/workflows/store/worker-pool.ts +55 -0
- package/src/workflows/store/worker-runtime.ts +90 -0
- package/src/ai/kit-skill.ts +0 -22
- package/src/ai/usage-migrate.ts +0 -81
- package/src/browser/notification-target.ts +0 -27
- package/src/contracts/notification-live.ts +0 -66
- package/src/server/services/freeipa/test-certificates.ts +0 -44
- package/src/services/notifications/live.ts +0 -50
- package/src/services/session/test-fixture.ts +0 -18
- package/src/ssr/BrowserNotifications.island.tsx +0 -135
- package/src/ssr/islands/SearchBar.island.tsx +0 -80
package/src/ai/routes.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Context, Hono } from "hono";
|
|
2
|
+
import { bodyLimit } from "hono/body-limit";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { listCapabilities } from "../_internal/registry";
|
|
4
5
|
import {
|
|
@@ -15,11 +16,16 @@ import {
|
|
|
15
16
|
respond,
|
|
16
17
|
v,
|
|
17
18
|
} from "../server";
|
|
19
|
+
import { logger } from "../services/logging";
|
|
18
20
|
import { coreSettings } from "../services/settings/api";
|
|
19
21
|
import type { AiToolApprovalContext } from "./approvals";
|
|
20
22
|
import { assistantAiSettingsState, listAssistantAiModels, selectAssistantAiModelId } from "./assistant-models";
|
|
23
|
+
import { AI_AUDIO_MAX_BYTES } from "./audio-format";
|
|
21
24
|
import { buildAiCapabilityCatalog } from "./capabilities";
|
|
25
|
+
import { getAiChatQuotas } from "./chat-quotas";
|
|
22
26
|
import { createConfiguredDefaultCloudAiTools } from "./default-tools";
|
|
27
|
+
import { enqueueAiDictation } from "./dictation-runtime";
|
|
28
|
+
import { AiDictationConflict, AiDictationListSchema, AiDictationStartSchema, aiDictations } from "./dictations";
|
|
23
29
|
import { aiProjectFilePathFromMount } from "./file-mount";
|
|
24
30
|
import { AI_FILES_MAX_FILE_BYTES_DEFAULT, aiFileStore, decodeAiFileContent, guessAiMediaType, normalizeAiFilePath } from "./files-store";
|
|
25
31
|
import {
|
|
@@ -41,6 +47,15 @@ import { aiMaintenanceJobs } from "./maintenance";
|
|
|
41
47
|
import { AI_MEMORY_CONTENT_MAX_CHARS, aiMemories } from "./memories";
|
|
42
48
|
import { aiMemoryLearningRuns } from "./memory-learning-runs";
|
|
43
49
|
import { createCloudAiMemoryTool } from "./memory-tool";
|
|
50
|
+
import {
|
|
51
|
+
AiMessageQueueConflict,
|
|
52
|
+
editQueuedMessage,
|
|
53
|
+
enqueueChatMessage,
|
|
54
|
+
listQueuedMessages,
|
|
55
|
+
queuedMessageAccepted,
|
|
56
|
+
updateQueuedMessage,
|
|
57
|
+
} from "./message-queue";
|
|
58
|
+
import { aiModelAccess } from "./model-access";
|
|
44
59
|
import { personalAiModelPolicy } from "./personal-agent";
|
|
45
60
|
import { aiActorUser, aiPrefsUserId, aiUserPrefs } from "./prefs";
|
|
46
61
|
import { aiProjects } from "./projects";
|
|
@@ -51,9 +66,11 @@ import {
|
|
|
51
66
|
AiTurnActionSchema,
|
|
52
67
|
abortAiTurn,
|
|
53
68
|
listPendingAiTurnActions,
|
|
69
|
+
prepareAiChatTurn,
|
|
54
70
|
submitAiChatTurn,
|
|
55
71
|
submitAiCompaction,
|
|
56
72
|
submitAiTurnAction,
|
|
73
|
+
wakeAiMessageQueue,
|
|
57
74
|
} from "./runtime";
|
|
58
75
|
import { readAiSettingsState, selectAiModelProfile } from "./settings";
|
|
59
76
|
import { AI_SHORT_ID_PATTERN } from "./short-id";
|
|
@@ -64,6 +81,7 @@ import { aiConversations } from "./store";
|
|
|
64
81
|
import { createAiConversationStreamResponse, loadAiStreamState } from "./stream";
|
|
65
82
|
import { composeAiSystemPrompt } from "./system-prompt";
|
|
66
83
|
import { aiToolPromptHints } from "./tools";
|
|
84
|
+
import { resolveAiAudioModel } from "./transcription";
|
|
67
85
|
import type { AiConversation, AiModelPolicy, AiTurn } from "./types";
|
|
68
86
|
|
|
69
87
|
/** Everything a resolved, authorized request needs to run against the shared runtime. */
|
|
@@ -102,6 +120,10 @@ const ConversationListQuerySchema = z
|
|
|
102
120
|
.enum(["true", "false"])
|
|
103
121
|
.transform((value) => value === "true")
|
|
104
122
|
.optional(),
|
|
123
|
+
done: z
|
|
124
|
+
.enum(["true", "false"])
|
|
125
|
+
.transform((value) => value === "true")
|
|
126
|
+
.optional(),
|
|
105
127
|
status: z.enum(["running", "needs_attention", "failed", "unread"]).optional(),
|
|
106
128
|
projectId: z.string().regex(AI_SHORT_ID_PATTERN).optional(),
|
|
107
129
|
unassigned: z
|
|
@@ -123,6 +145,7 @@ const ConversationMetadataInputSchema = z.object({
|
|
|
123
145
|
});
|
|
124
146
|
|
|
125
147
|
const ConversationProjectInputSchema = z.object({
|
|
148
|
+
onlyUnassigned: z.boolean().optional(),
|
|
126
149
|
projectId: z.string().regex(AI_SHORT_ID_PATTERN).nullable(),
|
|
127
150
|
});
|
|
128
151
|
|
|
@@ -212,12 +235,13 @@ const rememberLastUsedModel = (actor: RequestActor, modelProfileId: string | nul
|
|
|
212
235
|
};
|
|
213
236
|
|
|
214
237
|
const conversationDetail = async (conversation: AiConversation, subject: AccessSubject) => {
|
|
215
|
-
const [state, timeline] = await Promise.all([
|
|
238
|
+
const [state, timeline, publicView] = await Promise.all([
|
|
216
239
|
loadAiStreamState(conversation),
|
|
217
240
|
aiConversations.listConversationTimeline({ conversationId: conversation.id }),
|
|
241
|
+
publicConversationFor(conversation, subject),
|
|
218
242
|
]);
|
|
219
243
|
return {
|
|
220
|
-
conversation:
|
|
244
|
+
conversation: publicView,
|
|
221
245
|
messages: state.messages.map((message) => ({ ...message, id: message.shortId })),
|
|
222
246
|
hasMoreMessages: state.hasMoreMessages ?? false,
|
|
223
247
|
activeTurn: state.activeTurn,
|
|
@@ -284,6 +308,10 @@ export const aiRoutes = (() => {
|
|
|
284
308
|
.get("/status", async (c) => {
|
|
285
309
|
return respond(c, ok(await assistantAiSettingsState(c.get("accessSubject"))));
|
|
286
310
|
})
|
|
311
|
+
.get("/quotas", async (c) => {
|
|
312
|
+
c.header("Cache-Control", "no-store");
|
|
313
|
+
return c.json(await getAiChatQuotas(c.get("accessSubject")));
|
|
314
|
+
})
|
|
287
315
|
.get("/models", async (c) => {
|
|
288
316
|
return respond(c, ok(await listAssistantAiModels(c.get("accessSubject"))));
|
|
289
317
|
})
|
|
@@ -428,6 +456,7 @@ export const aiRoutes = (() => {
|
|
|
428
456
|
ownerUserId: ctx.ownerUserId,
|
|
429
457
|
search: query.q,
|
|
430
458
|
archived: query.archived,
|
|
459
|
+
done: query.done,
|
|
431
460
|
status: query.status,
|
|
432
461
|
projectId: project?.id,
|
|
433
462
|
unassigned: query.unassigned,
|
|
@@ -448,6 +477,7 @@ export const aiRoutes = (() => {
|
|
|
448
477
|
ownerUserId: ctx.ownerUserId,
|
|
449
478
|
search: query.q,
|
|
450
479
|
archived: query.archived,
|
|
480
|
+
done: query.done,
|
|
451
481
|
status: query.status,
|
|
452
482
|
projectId: project?.id,
|
|
453
483
|
unassigned: query.unassigned,
|
|
@@ -552,7 +582,7 @@ export const aiRoutes = (() => {
|
|
|
552
582
|
if (ctx instanceof Response) return ctx;
|
|
553
583
|
const conversation = await loadConversation(c, ctx);
|
|
554
584
|
if (!conversation) return notFound(c);
|
|
555
|
-
const messageId = c.req.param("messageId");
|
|
585
|
+
const messageId = c.req.param("messageId") ?? "";
|
|
556
586
|
if (!messageId) return respond(c, fail(err.badInput("Invalid message id.")));
|
|
557
587
|
const input = c.req.valid("json");
|
|
558
588
|
const feedback = await aiConversations.setMessageFeedback({
|
|
@@ -571,7 +601,7 @@ export const aiRoutes = (() => {
|
|
|
571
601
|
if (ctx instanceof Response) return ctx;
|
|
572
602
|
const conversation = await loadConversation(c, ctx);
|
|
573
603
|
if (!conversation) return notFound(c);
|
|
574
|
-
const messageId = c.req.param("messageId");
|
|
604
|
+
const messageId = c.req.param("messageId") ?? "";
|
|
575
605
|
if (!messageId) return respond(c, fail(err.badInput("Invalid message id.")));
|
|
576
606
|
return (await aiConversations.clearMessageFeedback({
|
|
577
607
|
conversationId: conversation.id,
|
|
@@ -650,8 +680,10 @@ export const aiRoutes = (() => {
|
|
|
650
680
|
conversationId: conversation.id,
|
|
651
681
|
ownerUserId: ctx.ownerUserId,
|
|
652
682
|
projectId: project?.id ?? null,
|
|
683
|
+
onlyUnassigned: body.onlyUnassigned,
|
|
653
684
|
});
|
|
654
685
|
if (!result.ok) {
|
|
686
|
+
if (result.reason === "already_assigned") return respond(c, fail(err.conflict("This chat already belongs to a Project.")));
|
|
655
687
|
if (result.reason === "active_turn") {
|
|
656
688
|
return respond(c, fail(err.conflict("Wait for the active turn before changing the Project.")));
|
|
657
689
|
}
|
|
@@ -683,6 +715,22 @@ export const aiRoutes = (() => {
|
|
|
683
715
|
});
|
|
684
716
|
return updated ? respond(c, ok(await publicConversationFor(updated, c.get("accessSubject")))) : notFound(c);
|
|
685
717
|
})
|
|
718
|
+
.put("/conversations/:conversationId/done", v("json", z.object({ done: z.boolean().nullable() })), async (c) => {
|
|
719
|
+
const ctx = await resolveContext(c);
|
|
720
|
+
if (ctx instanceof Response) return ctx;
|
|
721
|
+
const conversation = await loadConversation(c, ctx);
|
|
722
|
+
if (!conversation) return notFound(c);
|
|
723
|
+
const result = await aiConversations.setConversationDone({
|
|
724
|
+
conversationId: conversation.id,
|
|
725
|
+
ownerUserId: ctx.ownerUserId,
|
|
726
|
+
done: c.req.valid("json").done,
|
|
727
|
+
});
|
|
728
|
+
if (!result.ok)
|
|
729
|
+
return result.reason === "active_turn"
|
|
730
|
+
? respond(c, fail(err.conflict("Stop the current response before marking this chat done.")))
|
|
731
|
+
: notFound(c);
|
|
732
|
+
return respond(c, ok(await publicConversationFor(result.conversation, c.get("accessSubject"))));
|
|
733
|
+
})
|
|
686
734
|
.post("/conversations/:conversationId/archive", async (c) => {
|
|
687
735
|
const ctx = await resolveContext(c);
|
|
688
736
|
if (ctx instanceof Response) return ctx;
|
|
@@ -720,6 +768,43 @@ export const aiRoutes = (() => {
|
|
|
720
768
|
});
|
|
721
769
|
return viewed ? respond(c, ok({ ok: true })) : notFound(c);
|
|
722
770
|
})
|
|
771
|
+
.get("/conversations/:conversationId/queue", async (c) => {
|
|
772
|
+
const ctx = await resolveContext(c);
|
|
773
|
+
if (ctx instanceof Response) return ctx;
|
|
774
|
+
const conversation = await loadConversation(c, ctx);
|
|
775
|
+
return conversation ? respond(c, ok(await listQueuedMessages(conversation.id))) : notFound(c);
|
|
776
|
+
})
|
|
777
|
+
.patch(
|
|
778
|
+
"/conversations/:conversationId/queue/:messageId",
|
|
779
|
+
v("json", z.object({ text: z.string().trim().min(1).max(20000) }).strict()),
|
|
780
|
+
async (c) => {
|
|
781
|
+
const ctx = await resolveContext(c);
|
|
782
|
+
if (ctx instanceof Response) return ctx;
|
|
783
|
+
const conversation = await loadConversation(c, ctx);
|
|
784
|
+
if (!conversation || !z.uuid().safeParse(c.req.param("messageId")).success) return notFound(c);
|
|
785
|
+
return (await editQueuedMessage(conversation.id, c.req.param("messageId") ?? "", c.req.valid("json").text))
|
|
786
|
+
? respond(c, ok({ ok: true }))
|
|
787
|
+
: notFound(c);
|
|
788
|
+
},
|
|
789
|
+
)
|
|
790
|
+
.delete("/conversations/:conversationId/queue/:messageId", async (c) => {
|
|
791
|
+
const ctx = await resolveContext(c);
|
|
792
|
+
if (ctx instanceof Response) return ctx;
|
|
793
|
+
const conversation = await loadConversation(c, ctx);
|
|
794
|
+
if (!conversation || !z.uuid().safeParse(c.req.param("messageId")).success) return notFound(c);
|
|
795
|
+
if (!(await updateQueuedMessage(conversation.id, c.req.param("messageId") ?? "", "cancel"))) return notFound(c);
|
|
796
|
+
wakeAiMessageQueue(conversation.id);
|
|
797
|
+
return respond(c, ok({ ok: true }));
|
|
798
|
+
})
|
|
799
|
+
.post("/conversations/:conversationId/queue/:messageId/retry", async (c) => {
|
|
800
|
+
const ctx = await resolveContext(c);
|
|
801
|
+
if (ctx instanceof Response) return ctx;
|
|
802
|
+
const conversation = await loadConversation(c, ctx);
|
|
803
|
+
if (!conversation || !z.uuid().safeParse(c.req.param("messageId")).success) return notFound(c);
|
|
804
|
+
if (!(await updateQueuedMessage(conversation.id, c.req.param("messageId") ?? "", "retry"))) return notFound(c);
|
|
805
|
+
wakeAiMessageQueue(conversation.id);
|
|
806
|
+
return respond(c, ok({ ok: true }));
|
|
807
|
+
})
|
|
723
808
|
.put("/conversations/:conversationId/draft", v("json", AiSaveConversationDraftInputSchema), async (c) => {
|
|
724
809
|
const ctx = await resolveContext(c);
|
|
725
810
|
if (ctx instanceof Response) return ctx;
|
|
@@ -749,6 +834,7 @@ export const aiRoutes = (() => {
|
|
|
749
834
|
const conversation = await loadConversation(c, ctx);
|
|
750
835
|
if (!conversation) return notFound(c);
|
|
751
836
|
const body = c.req.valid("json");
|
|
837
|
+
if (body.queueId && (await queuedMessageAccepted(conversation.id, body.queueId))) return respond(c, ok({ queued: true }));
|
|
752
838
|
if (conversation.draft.revision !== body.draftRevision) {
|
|
753
839
|
return respond(c, fail(err.conflict("The conversation draft changed in another session.")));
|
|
754
840
|
}
|
|
@@ -756,6 +842,7 @@ export const aiRoutes = (() => {
|
|
|
756
842
|
const resourceParts = conversation.draft.content.filter((part) => part.type === "resource");
|
|
757
843
|
const turnContent = conversation.draft.content.map((part) => {
|
|
758
844
|
if (part.type === "text") return { type: "text" as const, text: part.text };
|
|
845
|
+
if (part.type === "project-file") return { type: "text" as const, text: `Project file: ${part.path}` };
|
|
759
846
|
if (part.type === "file") {
|
|
760
847
|
return { type: "attachment" as const, path: part.path, mediaType: part.mediaType, size: part.size };
|
|
761
848
|
}
|
|
@@ -768,8 +855,8 @@ export const aiRoutes = (() => {
|
|
|
768
855
|
const project = conversation.projectId ? await aiProjects.snapshot(conversation.projectId, c.get("accessSubject")) : null;
|
|
769
856
|
if (conversation.projectId && !project) return respond(c, fail(err.notFound("Project")));
|
|
770
857
|
try {
|
|
771
|
-
const
|
|
772
|
-
assistantChat: true,
|
|
858
|
+
const submission = {
|
|
859
|
+
assistantChat: true as const,
|
|
773
860
|
conversationId: conversation.id,
|
|
774
861
|
chatId: conversation.shortId,
|
|
775
862
|
input,
|
|
@@ -780,7 +867,7 @@ export const aiRoutes = (() => {
|
|
|
780
867
|
modelPolicy: ctx.modelPolicy,
|
|
781
868
|
project: project ?? undefined,
|
|
782
869
|
clientToolIds: body.clientToolIds,
|
|
783
|
-
toolSource: { kind: "default", appTools: true },
|
|
870
|
+
toolSource: { kind: "default" as const, appTools: true },
|
|
784
871
|
toolApprovalContext: ctx.toolApprovalContext,
|
|
785
872
|
expectedDraftRevision: body.draftRevision,
|
|
786
873
|
expectedProjectId: conversation.projectId,
|
|
@@ -788,7 +875,13 @@ export const aiRoutes = (() => {
|
|
|
788
875
|
expectedFiles: conversation.draft.content.flatMap((part) =>
|
|
789
876
|
part.type === "file" ? [{ path: part.path, version: part.version }] : [],
|
|
790
877
|
),
|
|
791
|
-
}
|
|
878
|
+
};
|
|
879
|
+
if (body.queueId) {
|
|
880
|
+
await enqueueChatMessage(body.queueId, await prepareAiChatTurn(submission), conversation.draft.content);
|
|
881
|
+
wakeAiMessageQueue(conversation.id);
|
|
882
|
+
return respond(c, ok({ queued: true }));
|
|
883
|
+
}
|
|
884
|
+
const result = await submitAiChatTurn(submission);
|
|
792
885
|
rememberLastUsedModel(ctx.actor, result.turn.modelProfileId);
|
|
793
886
|
return respond(
|
|
794
887
|
c,
|
|
@@ -803,6 +896,11 @@ export const aiRoutes = (() => {
|
|
|
803
896
|
201,
|
|
804
897
|
);
|
|
805
898
|
} catch (error) {
|
|
899
|
+
if (
|
|
900
|
+
error instanceof AiMessageQueueConflict ||
|
|
901
|
+
(error instanceof Error && error.message === "Queued messages must be sent first.")
|
|
902
|
+
)
|
|
903
|
+
return respond(c, fail(err.conflict(error.message)));
|
|
806
904
|
return toAiErrorResponse(c, error);
|
|
807
905
|
}
|
|
808
906
|
})
|
|
@@ -832,7 +930,7 @@ export const aiRoutes = (() => {
|
|
|
832
930
|
if (ctx instanceof Response) return ctx;
|
|
833
931
|
const conversation = await loadConversation(c, ctx);
|
|
834
932
|
if (!conversation) return notFound(c);
|
|
835
|
-
const messageId = c.req.param("messageId");
|
|
933
|
+
const messageId = c.req.param("messageId") ?? "";
|
|
836
934
|
|
|
837
935
|
const messages = await aiConversations.listMessages({ conversationId: conversation.id });
|
|
838
936
|
const target = messages.find((m) => m.shortId === messageId);
|
|
@@ -881,6 +979,7 @@ export const aiRoutes = (() => {
|
|
|
881
979
|
truncateFromSeq: target.seq,
|
|
882
980
|
fileSnapshot: originalRunConfig?.kind !== "compact" ? originalRunConfig?.files : undefined,
|
|
883
981
|
retrySourceTurnId: target.loopId ?? undefined,
|
|
982
|
+
clientToolIds: originalRunConfig?.kind !== "compact" ? originalRunConfig?.clientToolIds : undefined,
|
|
884
983
|
});
|
|
885
984
|
rememberLastUsedModel(ctx.actor, result.turn.modelProfileId);
|
|
886
985
|
return respond(
|
|
@@ -904,7 +1003,7 @@ export const aiRoutes = (() => {
|
|
|
904
1003
|
if (ctx instanceof Response) return ctx;
|
|
905
1004
|
const conversation = await loadConversation(c, ctx);
|
|
906
1005
|
if (!conversation) return notFound(c);
|
|
907
|
-
const messageId = c.req.param("messageId");
|
|
1006
|
+
const messageId = c.req.param("messageId") ?? "";
|
|
908
1007
|
|
|
909
1008
|
const messages = await aiConversations.listMessages({ conversationId: conversation.id });
|
|
910
1009
|
const target = messages.find((m) => m.shortId === messageId);
|
|
@@ -1029,6 +1128,130 @@ export const aiRoutes = (() => {
|
|
|
1029
1128
|
const files = await aiFileStore.list({ conversationId: conversation.id, prefix: c.req.valid("query").prefix ?? "/" });
|
|
1030
1129
|
return respond(c, ok({ files, totalBytes: await aiFileStore.totalBytes(conversation.id) }));
|
|
1031
1130
|
})
|
|
1131
|
+
.post("/conversations/:conversationId/dictations", bodyLimit({ maxSize: AI_AUDIO_MAX_BYTES + 65_536 }), async (c) => {
|
|
1132
|
+
const ctx = await resolveContext(c);
|
|
1133
|
+
if (ctx instanceof Response) return ctx;
|
|
1134
|
+
const conversation = await loadConversation(c, ctx);
|
|
1135
|
+
if (!conversation) return notFound(c);
|
|
1136
|
+
try {
|
|
1137
|
+
const form = await c.req.formData();
|
|
1138
|
+
const file = form.get("file");
|
|
1139
|
+
if (!(file instanceof File)) return respond(c, fail(err.badInput("Attach one audio recording.")));
|
|
1140
|
+
const options = AiDictationStartSchema.parse({
|
|
1141
|
+
operationId: form.get("operationId"),
|
|
1142
|
+
language: form.get("language") ?? undefined,
|
|
1143
|
+
});
|
|
1144
|
+
const dictation = await aiDictations.start({
|
|
1145
|
+
...options,
|
|
1146
|
+
conversationId: conversation.id,
|
|
1147
|
+
userId: ctx.ownerUserId,
|
|
1148
|
+
bytes: new Uint8Array(await file.arrayBuffer()),
|
|
1149
|
+
resolveModel: async () => {
|
|
1150
|
+
const model = await resolveAiAudioModel({ allowedDataBoundaries: ctx.modelPolicy.allowedDataBoundaries });
|
|
1151
|
+
await aiModelAccess.assertAllowed(model.profile.id, c.get("accessSubject"));
|
|
1152
|
+
return model;
|
|
1153
|
+
},
|
|
1154
|
+
});
|
|
1155
|
+
await enqueueAiDictation(dictation.id).catch(() => undefined); // The DB sweep heals failed delivery.
|
|
1156
|
+
return respond(c, ok(dictation));
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
return respond(
|
|
1159
|
+
c,
|
|
1160
|
+
fail(
|
|
1161
|
+
error instanceof AiDictationConflict
|
|
1162
|
+
? err.conflict(error.message)
|
|
1163
|
+
: err.badInput(error instanceof Error ? error.message : "Recording upload failed."),
|
|
1164
|
+
),
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
})
|
|
1168
|
+
.post("/conversations/:conversationId/dictations/discard", v("json", z.object({ operationId: z.uuid() })), async (c) => {
|
|
1169
|
+
const ctx = await resolveContext(c);
|
|
1170
|
+
if (ctx instanceof Response) return ctx;
|
|
1171
|
+
const conversation = await loadConversation(c, ctx);
|
|
1172
|
+
if (!conversation) return notFound(c);
|
|
1173
|
+
return respond(
|
|
1174
|
+
c,
|
|
1175
|
+
ok(
|
|
1176
|
+
await aiDictations.discardOperation({
|
|
1177
|
+
conversationId: conversation.id,
|
|
1178
|
+
userId: ctx.ownerUserId,
|
|
1179
|
+
operationId: c.req.valid("json").operationId,
|
|
1180
|
+
}),
|
|
1181
|
+
),
|
|
1182
|
+
);
|
|
1183
|
+
})
|
|
1184
|
+
.get("/conversations/:conversationId/dictations", v("query", AiDictationListSchema), async (c) => {
|
|
1185
|
+
const ctx = await resolveContext(c);
|
|
1186
|
+
if (ctx instanceof Response) return ctx;
|
|
1187
|
+
const conversation = await loadConversation(c, ctx);
|
|
1188
|
+
if (!conversation) return notFound(c);
|
|
1189
|
+
return respond(
|
|
1190
|
+
c,
|
|
1191
|
+
ok(await aiDictations.list({ ...c.req.valid("query"), conversationId: conversation.id, userId: ctx.ownerUserId })),
|
|
1192
|
+
);
|
|
1193
|
+
})
|
|
1194
|
+
.get("/conversations/:conversationId/dictations/:dictationId", async (c) => {
|
|
1195
|
+
const ctx = await resolveContext(c);
|
|
1196
|
+
if (ctx instanceof Response) return ctx;
|
|
1197
|
+
const conversation = await loadConversation(c, ctx);
|
|
1198
|
+
if (!conversation) return notFound(c);
|
|
1199
|
+
const result = await aiDictations.get({
|
|
1200
|
+
conversationId: conversation.id,
|
|
1201
|
+
userId: ctx.ownerUserId,
|
|
1202
|
+
id: z.string().regex(AI_SHORT_ID_PATTERN).parse(c.req.param("dictationId")),
|
|
1203
|
+
});
|
|
1204
|
+
return result ? respond(c, ok(result)) : notFound(c);
|
|
1205
|
+
})
|
|
1206
|
+
.post("/conversations/:conversationId/dictations/:dictationId/apply", v("json", AiSaveConversationDraftInputSchema), async (c) => {
|
|
1207
|
+
const ctx = await resolveContext(c);
|
|
1208
|
+
if (ctx instanceof Response) return ctx;
|
|
1209
|
+
const conversation = await loadConversation(c, ctx);
|
|
1210
|
+
if (!conversation) return notFound(c);
|
|
1211
|
+
try {
|
|
1212
|
+
return respond(
|
|
1213
|
+
c,
|
|
1214
|
+
ok(
|
|
1215
|
+
await aiDictations.apply({
|
|
1216
|
+
...c.req.valid("json"),
|
|
1217
|
+
conversationId: conversation.id,
|
|
1218
|
+
userId: ctx.ownerUserId,
|
|
1219
|
+
id: z.string().regex(AI_SHORT_ID_PATTERN).parse(c.req.param("dictationId")),
|
|
1220
|
+
}),
|
|
1221
|
+
),
|
|
1222
|
+
);
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
return respond(
|
|
1225
|
+
c,
|
|
1226
|
+
fail(
|
|
1227
|
+
error instanceof AiDictationConflict
|
|
1228
|
+
? err.conflict(error.message)
|
|
1229
|
+
: err.badInput(error instanceof Error ? error.message : "Dictation could not be inserted."),
|
|
1230
|
+
),
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
})
|
|
1234
|
+
.post(
|
|
1235
|
+
"/conversations/:conversationId/dictations/:dictationId/action",
|
|
1236
|
+
v("json", z.object({ action: z.enum(["discard", "retry"]) })),
|
|
1237
|
+
async (c) => {
|
|
1238
|
+
const ctx = await resolveContext(c);
|
|
1239
|
+
if (ctx instanceof Response) return ctx;
|
|
1240
|
+
const conversation = await loadConversation(c, ctx);
|
|
1241
|
+
if (!conversation) return notFound(c);
|
|
1242
|
+
const input = {
|
|
1243
|
+
conversationId: conversation.id,
|
|
1244
|
+
userId: ctx.ownerUserId,
|
|
1245
|
+
id: z.string().regex(AI_SHORT_ID_PATTERN).parse(c.req.param("dictationId")),
|
|
1246
|
+
};
|
|
1247
|
+
if (c.req.valid("json").action === "discard") await aiDictations.discard(input);
|
|
1248
|
+
else {
|
|
1249
|
+
await aiDictations.retry(input);
|
|
1250
|
+
await enqueueAiDictation(input.id).catch(() => undefined);
|
|
1251
|
+
}
|
|
1252
|
+
return respond(c, ok({ success: true }));
|
|
1253
|
+
},
|
|
1254
|
+
)
|
|
1032
1255
|
.post("/conversations/:conversationId/files", async (c) => {
|
|
1033
1256
|
const ctx = await resolveContext(c);
|
|
1034
1257
|
if (ctx instanceof Response) return ctx;
|
|
@@ -1042,7 +1265,9 @@ export const aiRoutes = (() => {
|
|
|
1042
1265
|
return respond(c, fail(err.badInput(`File exceeds the ${Math.floor(AI_FILES_MAX_FILE_BYTES_DEFAULT / (1024 * 1024))} MB limit`)));
|
|
1043
1266
|
}
|
|
1044
1267
|
const name = (file.name || "upload").replaceAll("/", "_").replaceAll("\\", "_").replaceAll("\0", "").slice(0, 160) || "upload";
|
|
1045
|
-
const
|
|
1268
|
+
const directory = form?.get("directory") ?? "/";
|
|
1269
|
+
if (typeof directory !== "string") return respond(c, fail(err.badInput("Invalid directory")));
|
|
1270
|
+
const path = normalizeAiFilePath(`${directory.replace(/\/$/, "")}/${name}`);
|
|
1046
1271
|
if (!path) return respond(c, fail(err.badInput("Invalid file name")));
|
|
1047
1272
|
if (aiProjectFilePathFromMount(path) !== null) return respond(c, fail(err.badInput("The /project namespace is reserved.")));
|
|
1048
1273
|
|
|
@@ -1055,6 +1280,11 @@ export const aiRoutes = (() => {
|
|
|
1055
1280
|
});
|
|
1056
1281
|
return respond(c, ok({ file: stat }));
|
|
1057
1282
|
} catch (error) {
|
|
1283
|
+
logger("ai:files").warn("Conversation upload failed", {
|
|
1284
|
+
code: "file_upload_failed",
|
|
1285
|
+
conversationId: conversation.id,
|
|
1286
|
+
errorType: error instanceof Error ? error.name : "unknown",
|
|
1287
|
+
});
|
|
1058
1288
|
return respond(c, fail(err.badInput(error instanceof Error ? error.message : "Upload failed")));
|
|
1059
1289
|
}
|
|
1060
1290
|
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Preserve why execution stopped instead of reporting an operator deadline as a user abort. */
|
|
2
|
+
export class AiRunTimeout extends Error {
|
|
3
|
+
constructor(readonly budgetMs: number | null) {
|
|
4
|
+
super("AI_RUN_TIMEOUT");
|
|
5
|
+
}
|
|
6
|
+
messageFor(locale?: string): string {
|
|
7
|
+
const minutes = this.budgetMs ? this.budgetMs / 60_000 : null;
|
|
8
|
+
return locale?.startsWith("de")
|
|
9
|
+
? `Laufzeitlimit${minutes ? ` von ${minutes} Minuten` : ""} erreicht. Du kannst die Aufgabe mit einer neuen Nachricht fortsetzen.`
|
|
10
|
+
: `Run time limit${minutes ? ` of ${minutes} minutes` : ""} reached. You can continue the task with a new message.`;
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/ai/runtime-tools.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
export { CloudAiTranscribeAudioInputSchema, CloudAiTranscribeAudioOutputSchema, createCloudAiTranscribeAudioTool } from "./audio-tool";
|
|
1
2
|
export {
|
|
2
3
|
CLOUD_AI_DEFERRED_BUILTIN_TOOL_NAMES,
|
|
3
4
|
createCloudAiCardTool,
|
|
5
|
+
createCloudAiCodeTools,
|
|
4
6
|
createCloudAiLocalBashTool,
|
|
5
7
|
createCloudAiSurveyTool,
|
|
6
8
|
createCloudAiTextEditorTool,
|
|
7
9
|
createConfiguredDefaultCloudAiTools,
|
|
8
10
|
createDefaultCloudAiTools,
|
|
9
11
|
} from "./default-tools";
|
|
12
|
+
export {
|
|
13
|
+
CloudAiFetchFileInputSchema,
|
|
14
|
+
CloudAiFetchFileOutputSchema,
|
|
15
|
+
createCloudAiFetchFileTool,
|
|
16
|
+
} from "./fetch-file-tool";
|
|
10
17
|
export {
|
|
11
18
|
CloudAiCalculateInputSchema,
|
|
12
19
|
CloudAiCalculateOutputSchema,
|
|
@@ -26,11 +33,6 @@ export {
|
|
|
26
33
|
evaluateAiDate,
|
|
27
34
|
evaluateAiMath,
|
|
28
35
|
} from "./file-tools";
|
|
29
|
-
export {
|
|
30
|
-
CloudAiFetchFileInputSchema,
|
|
31
|
-
CloudAiFetchFileOutputSchema,
|
|
32
|
-
createCloudAiFetchFileTool,
|
|
33
|
-
} from "./fetch-file-tool";
|
|
34
36
|
export {
|
|
35
37
|
CloudAiMarkdownToPdfInputSchema,
|
|
36
38
|
CloudAiMarkdownToPdfOutputSchema,
|