@k2b/cloud 0.43.0 → 0.45.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 +11 -2
- package/src/_internal/app-access-request.ts +13 -0
- package/src/_internal/app-access-resources.ts +141 -0
- package/src/_internal/app-event-catalog.ts +40 -0
- package/src/_internal/app-event-schemas.ts +127 -0
- package/src/_internal/application-package.ts +40 -0
- package/src/_internal/built-in-app-ids.json +27 -0
- package/src/_internal/capabilities.ts +158 -12
- package/src/_internal/capability-origin.ts +4 -0
- package/src/_internal/capability-streams.ts +7 -5
- package/src/_internal/define-app.ts +57 -6
- package/src/_internal/object-store-area.ts +9 -0
- package/src/_internal/object-store-config.ts +101 -0
- package/src/_internal/object-store-key.ts +14 -0
- package/src/_internal/process-identity.ts +7 -2
- package/src/_internal/registry-validation.ts +11 -1
- package/src/_internal/registry.ts +8 -1
- package/src/_internal/runtime-context.ts +8 -1
- package/src/access/AppAccessEditor.tsx +2 -0
- package/src/access/GroupCoverage.tsx +20 -5
- package/src/access/PermissionEditor.tsx +20 -5
- package/src/access/PrincipalAvatar.tsx +30 -21
- package/src/access/PrincipalPicker.tsx +14 -4
- package/src/access/ResourceApiKeys.tsx +3 -4
- package/src/access/app-access-messages.ts +6 -0
- package/src/access/messages.ts +4 -4
- package/src/account/EntitySearch.tsx +12 -0
- package/src/account/ProfilePictureDialog.tsx +699 -0
- package/src/account/profile-picture-messages.ts +269 -0
- package/src/account/ui.ts +7 -0
- package/src/ai/admin.ts +3 -0
- package/src/ai/app-frame.ts +12 -0
- package/src/ai/application-tasks.ts +101 -0
- package/src/ai/assistant-models.ts +126 -64
- package/src/ai/capabilities.ts +19 -4
- package/src/ai/chart-block.ts +63 -30
- package/src/ai/chat/chart-block.tsx +12 -3
- package/src/ai/chat/composer-adapter.ts +8 -7
- package/src/ai/chat/message-actions.tsx +1 -1
- package/src/ai/chat/message-utils.ts +2 -2
- package/src/ai/chat/presentation.tsx +22 -1
- package/src/ai/chat-quotas.ts +5 -4
- package/src/ai/chat-tasks.ts +2 -2
- package/src/ai/client/controller.ts +11 -10
- package/src/ai/client/projection.ts +3 -3
- package/src/ai/compaction.ts +3 -3
- package/src/ai/credentials.ts +13 -114
- package/src/ai/default-tool-contracts.ts +4 -3
- package/src/ai/dictation-runtime.ts +10 -6
- package/src/ai/enrich.ts +2 -2
- package/src/ai/executor.ts +40 -25
- package/src/ai/http.ts +17 -29
- package/src/ai/index.ts +12 -5
- package/src/ai/inference-calls.ts +5 -4
- package/src/ai/maintenance.ts +1 -1
- package/src/ai/memory-learning-runs.ts +5 -5
- package/src/ai/memory-learning.ts +3 -3
- package/src/ai/message-queue.ts +1 -2
- package/src/ai/migrate.ts +75 -42
- package/src/ai/model-access-migrate.ts +3 -17
- package/src/ai/model-access.ts +44 -85
- package/src/ai/model-card.tsx +134 -0
- package/src/ai/model-catalog.ts +359 -0
- package/src/ai/model-chooser-messages.ts +88 -0
- package/src/ai/model-chooser.tsx +577 -0
- package/src/ai/model-delete.ts +234 -0
- package/src/ai/model-fixture.ts +39 -0
- package/src/ai/model-icon.tsx +36 -0
- package/src/ai/model-overview.ts +53 -0
- package/src/ai/model-usage.ts +45 -0
- package/src/ai/openai-api-messages.ts +0 -4
- package/src/ai/openai-api.ts +26 -9
- package/src/ai/personal-agent.ts +1 -1
- package/src/ai/prefs.ts +12 -10
- package/src/ai/project-tool.ts +4 -4
- package/src/ai/projects-authorization.ts +53 -0
- package/src/ai/projects-routes.ts +58 -47
- package/src/ai/projects.ts +110 -88
- package/src/ai/protocol.ts +2 -2
- package/src/ai/provider-connections.ts +161 -0
- package/src/ai/provider-errors.ts +55 -6
- package/src/ai/provider-fetch.ts +4 -0
- package/src/ai/provider.ts +1 -1
- package/src/ai/quota-limits.ts +36 -0
- package/src/ai/quota-provider.ts +4 -2
- package/src/ai/quota-report.ts +7 -4
- package/src/ai/quotas.ts +19 -8
- package/src/ai/recent-resources.ts +9 -3
- package/src/ai/request-headers.ts +14 -87
- package/src/ai/resource-refs.ts +6 -2
- package/src/ai/routes.ts +47 -48
- package/src/ai/runtime.ts +50 -22
- package/src/ai/settings.ts +93 -580
- package/src/ai/skill-tool.ts +4 -4
- package/src/ai/skills-routes.ts +27 -26
- package/src/ai/skills.ts +120 -81
- package/src/ai/store.ts +45 -23
- package/src/ai/stream.ts +1 -1
- package/src/ai/structured-runs.ts +2 -2
- package/src/ai/structured.ts +21 -44
- package/src/ai/task-contracts.ts +25 -5
- package/src/ai/task-execution.ts +15 -6
- package/src/ai/task-model.ts +9 -0
- package/src/ai/transcription.ts +27 -22
- package/src/ai/types.ts +50 -62
- package/src/ai/ui.tsx +13 -0
- package/src/ai/usage.ts +8 -8
- package/src/ai/validate.ts +8 -7
- package/src/ai/view-block.ts +2 -2
- package/src/api/accounts-entities.ts +22 -3
- package/src/api/admin-ai-quotas.ts +34 -56
- package/src/api/admin-ai-skills.ts +4 -1
- package/src/api/admin-ai-usage.ts +1 -1
- package/src/api/admin-ai.ts +173 -0
- package/src/api/admin-core-settings.ts +68 -244
- package/src/api/app-approval.ts +3 -1
- package/src/api/app-event-delivery.ts +51 -0
- package/src/api/app-events.ts +123 -0
- package/src/api/app-resource-access.ts +48 -0
- package/src/api/auth/account-mismatch.ts +24 -0
- package/src/api/auth.ts +35 -5
- package/src/api/capabilities.ts +28 -4
- package/src/api/index.ts +7 -1
- package/src/api/mcp.ts +175 -2
- package/src/api/me.ts +6 -4
- package/src/api/pwa-phone.ts +75 -26
- package/src/api/pwa.ts +34 -8
- package/src/api/resource-links.ts +83 -6
- package/src/api/resource-resolve.ts +50 -0
- package/src/api/search/schemas.ts +3 -1
- package/src/api/search.ts +9 -7
- package/src/app-pwa/contracts.ts +4 -0
- package/src/app-pwa/core-query-error.ts +20 -0
- package/src/app-pwa/index.ts +1 -0
- package/src/app-pwa/service.ts +91 -0
- package/src/app-pwa/transport.ts +22 -0
- package/src/approvals/messages.ts +2 -2
- package/src/browser/cloud-id.ts +86 -0
- package/src/browser/resource-clipboard.ts +4 -0
- package/src/browser/resource-links.ts +52 -0
- package/src/browser/session.ts +39 -0
- package/src/browser/shared-text-history-validation.ts +151 -0
- package/src/browser/shared-text-history.ts +464 -0
- package/src/browser/shared-text-offline-authorized.ts +29 -0
- package/src/browser/shared-text-offline.ts +351 -0
- package/src/browser/shared-text-provider.ts +714 -0
- package/src/browser/shared-text-table-contract.ts +150 -0
- package/src/browser/shared-text.ts +19 -0
- package/src/capabilities/server-invoke.ts +2 -11
- package/src/capabilities/testing.ts +5 -2
- package/src/cli/access.ts +6 -5
- package/src/cli/admin/ai-models.ts +199 -0
- package/src/cli/admin/ai-quotas.ts +6 -102
- package/src/cli/admin/ai-usage.ts +4 -4
- package/src/cli/admin/app-credentials.ts +5 -3
- package/src/cli/admin/index.ts +5 -2
- package/src/cli/apps.ts +89 -26
- package/src/cli/capabilities.ts +22 -1
- package/src/cli/events.ts +320 -0
- package/src/config/env.ts +40 -0
- package/src/contracts/app-access.ts +26 -2
- package/src/contracts/app-details.ts +89 -0
- package/src/contracts/app-events.ts +51 -0
- package/src/contracts/app.ts +21 -5
- package/src/contracts/capabilities.ts +143 -3
- package/src/contracts/index.ts +2 -0
- package/src/contracts/notification-types.ts +36 -9
- package/src/contracts/pwa.ts +17 -1
- package/src/contracts/registry.ts +6 -0
- package/src/contracts/resource-clipboard.ts +35 -0
- package/src/contracts/resource-pages.ts +140 -0
- package/src/contracts/resource-resolution.ts +13 -0
- package/src/contracts/shared.ts +6 -1
- package/src/contracts/user-notifications.ts +2 -0
- package/src/events/app-event-delivery.ts +100 -0
- package/src/events/app-events.testing.ts +65 -0
- package/src/events/app-events.ts +134 -0
- package/src/events/core-user-created.ts +24 -0
- package/src/events/index.ts +9 -0
- package/src/events/testing.ts +2 -0
- package/src/index.ts +1 -1
- package/src/server/api/respond.ts +17 -4
- package/src/server/index.ts +2 -0
- package/src/server/middleware/app-access.ts +1 -1
- package/src/server/middleware/auth.ts +21 -7
- package/src/server/middleware/index.ts +1 -0
- package/src/server/middleware/invocation.ts +2 -0
- package/src/server/public-storage.ts +106 -0
- package/src/server/services/access.ts +31 -10
- package/src/server/services/index.ts +1 -0
- package/src/services/accounts/app.ts +36 -13
- package/src/services/accounts/entities.ts +43 -19
- package/src/services/accounts/group-sql.ts +23 -0
- package/src/services/accounts/groups.ts +19 -14
- package/src/services/accounts/identities.ts +70 -11
- package/src/services/accounts/identity-reconciliation.ts +3 -1
- package/src/services/accounts/local-groups.ts +69 -4
- package/src/services/accounts/users.ts +45 -14
- package/src/services/app-access.ts +25 -7
- package/src/services/app-details.ts +224 -0
- package/src/services/app-discovery.ts +2 -1
- package/src/services/app-event-shapes.ts +139 -0
- package/src/services/app-events/accept.ts +116 -0
- package/src/services/app-events/admin.ts +250 -0
- package/src/services/app-events/declarations.ts +187 -0
- package/src/services/app-events/deliver.ts +218 -0
- package/src/services/app-events.ts +92 -0
- package/src/services/config-conflict.ts +11 -0
- package/src/services/core-user-events.ts +1 -0
- package/src/services/freeipa-config.ts +9 -0
- package/src/services/geo/ledger.ts +28 -10
- package/src/services/geo/service.ts +43 -24
- package/src/services/identity/core-origin.ts +12 -0
- package/src/services/identity/invocation-actor.ts +20 -2
- package/src/services/identity/invocation-authority.ts +4 -0
- package/src/services/identity/invocation-token.ts +238 -56
- package/src/services/identity/issue-invocation.ts +6 -1
- package/src/services/image-metadata.ts +65 -1
- package/src/services/index.ts +13 -1
- package/src/services/ipa/sync.ts +6 -2
- package/src/services/ipa/users.ts +4 -1
- package/src/services/mandates/index.ts +2 -2
- package/src/services/mandates/policy.ts +20 -12
- package/src/services/notifications/browser.ts +4 -0
- package/src/services/notifications/catalog.ts +5 -2
- package/src/services/notifications/platform.ts +7 -2
- package/src/services/notifications/user.ts +18 -7
- package/src/services/oauth-tokens.ts +28 -2
- package/src/services/object-store.ts +217 -0
- package/src/services/providers/local/users.ts +5 -0
- package/src/services/pwa-devices.ts +147 -37
- package/src/services/session/index.ts +26 -3
- package/src/services/settings/core-settings.ts +71 -43
- package/src/services/settings/index.ts +8 -0
- package/src/services/settings/versions.ts +26 -0
- package/src/shared/ai-models.ts +274 -0
- package/src/shared/ai-quotas.ts +2 -2
- package/src/shared/ai-usage.ts +2 -2
- package/src/shared/email-html.ts +1 -0
- package/src/shared/index.ts +2 -0
- package/src/shared/markdown/extensions/katex.ts +8 -1
- package/src/shared/markdown/extensions/tables.ts +14 -1
- package/src/shared/markdown/index.ts +22 -11
- package/src/shared-text/anchors.ts +29 -0
- package/src/shared-text/awareness.ts +87 -0
- package/src/shared-text/changes.ts +27 -0
- package/src/shared-text/documents.ts +433 -65
- package/src/shared-text/events.ts +12 -2
- package/src/shared-text/index.ts +16 -1
- package/src/shared-text/log.ts +24 -5
- package/src/shared-text/snapshots.ts +69 -23
- package/src/shared-text/structural-history.ts +377 -0
- package/src/shared-text/table-actions.ts +432 -0
- package/src/shared-text/text-diff.ts +75 -0
- package/src/shared-text/types.ts +24 -5
- package/src/ssr/AdminArea.tsx +131 -0
- package/src/ssr/AdminLayout.tsx +9 -3
- package/src/ssr/AdminSidebar.tsx +7 -7
- package/src/ssr/AppAccessDenied.tsx +2 -0
- package/src/ssr/AppBadge.tsx +14 -0
- package/src/ssr/AppLaunchpadPanel.tsx +2 -2
- package/src/ssr/CloudShell.island.tsx +44 -7
- package/src/ssr/Layout.tsx +9 -7
- package/src/ssr/MobileProfileActions.tsx +2 -2
- package/src/ssr/ProfilePreferences.tsx +2 -1
- package/src/ssr/PwaLayout.tsx +16 -1
- package/src/ssr/PwaPartCount.island.tsx +23 -0
- package/src/ssr/SettingsSaveOutcome.tsx +58 -0
- package/src/ssr/SettingsSaveStatus.island.tsx +16 -0
- package/src/ssr/__snapshots__/Layout.unchanged.render.test.tsx.snap +3 -3
- package/src/ssr/admin-active-link.ts +16 -0
- package/src/ssr/admin-navigation.ts +26 -31
- package/src/ssr/app-badges.ts +31 -7
- package/src/ssr/app-launchpad.tsx +6 -1
- package/src/ssr/index.ts +8 -0
- package/src/ssr/page-trail-runtime.ts +3 -1
- package/src/ssr/platform-messages.ts +11 -1
- package/src/ssr/profile-actions.ts +3 -6
- package/src/ssr/pwa-messages.ts +2 -2
- package/src/ssr/rail-navigation.ts +5 -1
- package/src/ssr/settings-draft.ts +153 -0
- package/src/ssr/shell-data.tsx +3 -1
- package/src/styles/global.css +1 -0
- package/src/styles/profile-picture.css +270 -0
- package/src/styles/utilities-navigation.css +6 -0
- package/src/workflows/ai/policy.ts +49 -0
- package/src/workflows/ai/runtime.ts +131 -21
- package/src/workflows/ai/store.ts +283 -35
- package/src/workflows/ai/types.ts +8 -2
- package/src/workflows/ai-actions.ts +148 -120
- package/src/workflows/authoring.ts +31 -0
- package/src/workflows/contracts.ts +1 -0
- package/src/workflows/definition.ts +2 -0
- package/src/workflows/editor.ts +15 -0
- package/src/workflows/index.ts +2 -1
- package/src/workflows/language/compiler.ts +34 -3
- package/src/workflows/language/expressions.ts +3 -2
- package/src/workflows/runtime/executor.ts +134 -34
- package/src/workflows/runtime/index.ts +2 -0
- package/src/workflows/runtime/ports.ts +5 -1
- package/src/workflows/store/actions.ts +1 -1
- package/src/workflows/store/definitions.ts +5 -0
- package/src/workflows/store/runs.ts +5 -3
- package/src/workflows/store/worker.ts +7 -2
- package/src/ai/model-pricing.ts +0 -43
- package/src/ai/model-request-settings.ts +0 -98
- package/src/ai/settings-messages.ts +0 -129
- package/src/shared/ai-model-request-settings.ts +0 -21
package/src/ai/resource-refs.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { AiConversationResourceObservation } from "./types";
|
|
|
13
13
|
|
|
14
14
|
const LinkedResourceReferenceSchema = CloudResourceReferenceSchema.extend({
|
|
15
15
|
href: CloudResourceHrefSchema.optional(),
|
|
16
|
-
});
|
|
16
|
+
}).strip();
|
|
17
17
|
|
|
18
18
|
export const addCloudResourceHrefs = <T>(
|
|
19
19
|
value: T,
|
|
@@ -67,12 +67,14 @@ export const collectConversationResourceObservations = (...values: unknown[]): A
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const view = CloudResourceViewSchema.safeParse(value);
|
|
70
|
+
const view = CloudResourceViewSchema.strip().safeParse(value);
|
|
71
71
|
if (view.success) {
|
|
72
72
|
const resource: CloudResourceView = view.data;
|
|
73
73
|
observations.set(observationKey(resource.ref), {
|
|
74
74
|
ref: resource.ref,
|
|
75
75
|
title: resource.title,
|
|
76
|
+
context: resource.context,
|
|
77
|
+
status: resource.status,
|
|
76
78
|
preview: resource.preview,
|
|
77
79
|
icon: resource.icon,
|
|
78
80
|
href: resource.links.find((link) => link.rel === "open")?.href,
|
|
@@ -87,6 +89,8 @@ export const collectConversationResourceObservations = (...values: unknown[]): A
|
|
|
87
89
|
...previous,
|
|
88
90
|
ref,
|
|
89
91
|
...(resource.title !== undefined ? { title: resource.title } : {}),
|
|
92
|
+
...(resource.context !== undefined ? { context: resource.context } : {}),
|
|
93
|
+
...(resource.status !== undefined ? { status: resource.status } : {}),
|
|
90
94
|
...(resource.preview !== undefined ? { preview: resource.preview } : {}),
|
|
91
95
|
...(resource.icon !== undefined ? { icon: resource.icon } : {}),
|
|
92
96
|
...(resource.href !== undefined ? { href: resource.href } : {}),
|
package/src/ai/routes.ts
CHANGED
|
@@ -8,7 +8,6 @@ import { ErrorResponseSchema } from "../contracts";
|
|
|
8
8
|
import { APPROVAL_CLIENT_HEADER } from "../contracts/approvals";
|
|
9
9
|
import { capabilityActionPolicy } from "../contracts/capabilities";
|
|
10
10
|
import {
|
|
11
|
-
type AccessSubject,
|
|
12
11
|
type AuthContext,
|
|
13
12
|
auth,
|
|
14
13
|
err,
|
|
@@ -37,7 +36,7 @@ import { coreSettings } from "../services/settings/api";
|
|
|
37
36
|
import { resolveAppIdentityPresentation } from "../shared/app-presentation";
|
|
38
37
|
import { readThemeFromCookieHeader } from "../shared/theme";
|
|
39
38
|
import { type AiStoredActionReview, isLegacyActionReview, isUnknownActionOutcome, storedActionReview } from "./action-review";
|
|
40
|
-
import { assistantAiSettingsState,
|
|
39
|
+
import { assistantAiSettingsState, peopleAiModels, resolveAssistantAudioModel, selectAssistantAiModel } from "./assistant-models";
|
|
41
40
|
import { AI_AUDIO_MAX_BYTES } from "./audio-format";
|
|
42
41
|
import { buildAiCapabilityCatalog } from "./capabilities";
|
|
43
42
|
import { checkAiCapability, resolveAiCapabilityActor } from "./capability-execution";
|
|
@@ -80,6 +79,7 @@ import {
|
|
|
80
79
|
} from "./message-queue";
|
|
81
80
|
import { aiActorUser, aiPrefsUserId, aiUserPrefs } from "./prefs";
|
|
82
81
|
import { aiProjects } from "./projects";
|
|
82
|
+
import type { AiResourceContext } from "./projects-authorization";
|
|
83
83
|
import { projectPublicAiStoredMessages, publicAiStoredMessages } from "./public-projection";
|
|
84
84
|
import { AiRecentResourceSchema, listAiRecentResources } from "./recent-resources";
|
|
85
85
|
import { RECENT_SENT_REF_LIMIT } from "./recent-sent-refs";
|
|
@@ -224,6 +224,8 @@ const MemoryCreateSchema = z.object({
|
|
|
224
224
|
const MemoryUpdateSchema = MemoryCreateSchema.partial().refine((value) => Object.keys(value).length > 0, "Pass a changed field.");
|
|
225
225
|
const MemoryIdSchema = z.string().regex(AI_SHORT_ID_PATTERN);
|
|
226
226
|
|
|
227
|
+
const resourceContext = (c: Context<AuthContext>): AiResourceContext => ({ actor: c.get("actor"), accessSubject: c.get("accessSubject") });
|
|
228
|
+
|
|
227
229
|
const notFound = (c: Context<AuthContext>) => respond(c, fail(err.notFound("Conversation")));
|
|
228
230
|
const fileNotFound = (c: Context<AuthContext>) => respond(c, fail(err.notFound("File")));
|
|
229
231
|
|
|
@@ -232,14 +234,14 @@ const publicConversation = (conversation: AiConversation, projectId: string | nu
|
|
|
232
234
|
id: conversation.shortId,
|
|
233
235
|
projectId: conversation.projectId ? projectId : null,
|
|
234
236
|
});
|
|
235
|
-
const publicConversations = async (conversations: AiConversation[], subject:
|
|
237
|
+
const publicConversations = async (conversations: AiConversation[], subject: AiResourceContext) => {
|
|
236
238
|
const projectIds = conversations.flatMap((conversation) => (conversation.projectId ? [conversation.projectId] : []));
|
|
237
239
|
const shortIds = await aiProjects.resolveShortIds(projectIds, subject);
|
|
238
240
|
return conversations.map((conversation) =>
|
|
239
241
|
publicConversation(conversation, conversation.projectId ? (shortIds.get(conversation.projectId) ?? null) : null),
|
|
240
242
|
);
|
|
241
243
|
};
|
|
242
|
-
const publicConversationFor = async (conversation: AiConversation, subject:
|
|
244
|
+
const publicConversationFor = async (conversation: AiConversation, subject: AiResourceContext) =>
|
|
243
245
|
(await publicConversations([conversation], subject))[0]!;
|
|
244
246
|
const publicMemories = async (userId: string, memories: Awaited<ReturnType<typeof aiMemories.list>>) => {
|
|
245
247
|
const sourceIds = memories.flatMap((memory) => (memory.sourceConversationId ? [memory.sourceConversationId] : []));
|
|
@@ -254,13 +256,13 @@ const publicMemory = async (userId: string, memory: Awaited<ReturnType<typeof ai
|
|
|
254
256
|
(await publicMemories(userId, [memory]))[0]!;
|
|
255
257
|
|
|
256
258
|
/** Fire-and-forget: remember the model this user actually ran a turn with (preselected for new chats). */
|
|
257
|
-
const rememberLastUsedModel = (actor: RequestActor,
|
|
259
|
+
const rememberLastUsedModel = (actor: RequestActor, model: import("../shared/ai-models").AiModelRequest | undefined): void => {
|
|
258
260
|
const userId = aiPrefsUserId(actor);
|
|
259
|
-
if (!userId || !
|
|
260
|
-
void aiUserPrefs.update(userId, {
|
|
261
|
+
if (!userId || !model) return;
|
|
262
|
+
void aiUserPrefs.update(userId, { selection: model }).catch(() => undefined);
|
|
261
263
|
};
|
|
262
264
|
|
|
263
|
-
const conversationDetail = async (conversation: AiConversation, subject:
|
|
265
|
+
const conversationDetail = async (conversation: AiConversation, subject: AiResourceContext) => {
|
|
264
266
|
const [state, timeline, publicView] = await Promise.all([
|
|
265
267
|
loadAiStreamState(conversation),
|
|
266
268
|
aiConversations.listConversationTimeline({ conversationId: conversation.id }),
|
|
@@ -297,7 +299,7 @@ const prepareConversationForMessageRetry = async (conversationId: string): Promi
|
|
|
297
299
|
|
|
298
300
|
const prepareLaunchDraft = async (
|
|
299
301
|
body: z.infer<typeof AiCreateConversationInputSchema>,
|
|
300
|
-
subject:
|
|
302
|
+
subject: AiResourceContext | null,
|
|
301
303
|
authority: import("../server").RequestAuthority | null = null,
|
|
302
304
|
) => {
|
|
303
305
|
const content = [...(body.draft?.content ?? [])];
|
|
@@ -348,7 +350,7 @@ export const aiRoutes = (() => {
|
|
|
348
350
|
return c.json(await getAiChatQuotas(c.get("accessSubject")));
|
|
349
351
|
})
|
|
350
352
|
.get("/models", async (c) => {
|
|
351
|
-
return respond(c, ok(await
|
|
353
|
+
return respond(c, ok(await peopleAiModels(c.get("accessSubject"))));
|
|
352
354
|
})
|
|
353
355
|
.get("/prefs", async (c) => {
|
|
354
356
|
const ctx = await resolveContext(c);
|
|
@@ -438,16 +440,15 @@ export const aiRoutes = (() => {
|
|
|
438
440
|
const state = await readAiSettingsState();
|
|
439
441
|
let previewProfile: ReturnType<typeof selectAiModelProfile> | null = null;
|
|
440
442
|
if (state.ok && state.enabled) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (preferredId) previewProfile = selectAiModelProfile(state, ctx.modelPolicy, preferredId);
|
|
443
|
+
try {
|
|
444
|
+
previewProfile = selectAiModelProfile(state, ctx.modelPolicy, prefs.selection ?? undefined);
|
|
445
|
+
} catch {
|
|
446
|
+
/* The prompt preview remains available without a usable model. */
|
|
447
|
+
}
|
|
447
448
|
}
|
|
448
449
|
const toolsSupported = Boolean(previewProfile?.capabilities.includes("tools"));
|
|
449
450
|
const availableSkills = toolsSupported
|
|
450
|
-
? (await aiSkills.list(c
|
|
451
|
+
? (await aiSkills.list(resourceContext(c), { authority: appAccessAuthority(c) })).filter((skill) => skill.enabled)
|
|
451
452
|
: [];
|
|
452
453
|
const skillCatalog = selectAiSkillCatalog(
|
|
453
454
|
availableSkills.filter((skill) => !skill.manualOnly).map(({ name, description }) => ({ name, description })),
|
|
@@ -462,8 +463,8 @@ export const aiRoutes = (() => {
|
|
|
462
463
|
})),
|
|
463
464
|
...(client?.localTools === "ask" ? [createCloudAiLocalBashTool(), ...createCloudAiLocalTools()] : []),
|
|
464
465
|
...(memoryEnabled ? [createCloudAiMemoryTool()] : []),
|
|
465
|
-
...(availableSkills.length ? [createCloudAiLoadSkillTool(c
|
|
466
|
-
...(skillCatalog.omitted > 0 ? [createCloudAiSearchSkillsTool(c
|
|
466
|
+
...(availableSkills.length ? [createCloudAiLoadSkillTool(resourceContext(c), appAccessAuthority(c))] : []),
|
|
467
|
+
...(skillCatalog.omitted > 0 ? [createCloudAiSearchSkillsTool(resourceContext(c), [], appAccessAuthority(c))] : []),
|
|
467
468
|
]
|
|
468
469
|
: [];
|
|
469
470
|
const memoryToolEnabled = tools.some((tool) => tool.def.name === "memory");
|
|
@@ -546,7 +547,7 @@ export const aiRoutes = (() => {
|
|
|
546
547
|
const ctx = await resolveContext(c);
|
|
547
548
|
if (ctx instanceof Response) return ctx;
|
|
548
549
|
const query = c.req.valid("query");
|
|
549
|
-
const project = query.projectId ? await aiProjects.getByShortId(query.projectId, c
|
|
550
|
+
const project = query.projectId ? await aiProjects.getByShortId(query.projectId, resourceContext(c), "read") : null;
|
|
550
551
|
if (query.projectId && !project) return respond(c, fail(err.notFound("Project")));
|
|
551
552
|
return respond(
|
|
552
553
|
c,
|
|
@@ -562,7 +563,7 @@ export const aiRoutes = (() => {
|
|
|
562
563
|
unassigned: query.unassigned,
|
|
563
564
|
limit: query.limit,
|
|
564
565
|
}),
|
|
565
|
-
c
|
|
566
|
+
resourceContext(c),
|
|
566
567
|
),
|
|
567
568
|
),
|
|
568
569
|
);
|
|
@@ -571,7 +572,7 @@ export const aiRoutes = (() => {
|
|
|
571
572
|
const ctx = await resolveContext(c);
|
|
572
573
|
if (ctx instanceof Response) return ctx;
|
|
573
574
|
const query = c.req.valid("query");
|
|
574
|
-
const project = query.projectId ? await aiProjects.getByShortId(query.projectId, c
|
|
575
|
+
const project = query.projectId ? await aiProjects.getByShortId(query.projectId, resourceContext(c), "read") : null;
|
|
575
576
|
if (query.projectId && !project) return respond(c, fail(err.notFound("Project")));
|
|
576
577
|
const page = await aiConversations.listConversationsPage({
|
|
577
578
|
ownerUserId: ctx.ownerUserId,
|
|
@@ -584,15 +585,15 @@ export const aiRoutes = (() => {
|
|
|
584
585
|
page: query.page ?? 1,
|
|
585
586
|
perPage: query.perPage ?? 20,
|
|
586
587
|
});
|
|
587
|
-
return respond(c, ok({ ...page, items: await publicConversations(page.items, c
|
|
588
|
+
return respond(c, ok({ ...page, items: await publicConversations(page.items, resourceContext(c)) }));
|
|
588
589
|
})
|
|
589
590
|
.post("/conversations", v("json", AiCreateConversationInputSchema), async (c) => {
|
|
590
591
|
const ctx = await resolveContext(c);
|
|
591
592
|
if (ctx instanceof Response) return ctx;
|
|
592
593
|
const body = c.req.valid("json");
|
|
593
|
-
const project = body.projectId ? await aiProjects.getByShortId(body.projectId, c
|
|
594
|
+
const project = body.projectId ? await aiProjects.getByShortId(body.projectId, resourceContext(c), "read") : null;
|
|
594
595
|
if (body.projectId && !project) return respond(c, fail(err.notFound("Project")));
|
|
595
|
-
const draft = await prepareLaunchDraft(body, c
|
|
596
|
+
const draft = await prepareLaunchDraft(body, resourceContext(c), appAccessAuthority(c));
|
|
596
597
|
if (!draft.ok) return respond(c, draft);
|
|
597
598
|
const requestedCapabilityTools = (body.preloadTools ?? []).filter(
|
|
598
599
|
(requested): requested is { appId: string; kind: "query" | "action"; id: string } => "appId" in requested,
|
|
@@ -643,9 +644,7 @@ export const aiRoutes = (() => {
|
|
|
643
644
|
launchedByAppId: body.launchedByAppId,
|
|
644
645
|
});
|
|
645
646
|
// A replay may return a conversation assigned to a Project since creation.
|
|
646
|
-
const currentProject = conversation.projectId
|
|
647
|
-
? await aiProjects.get(conversation.projectId, c.get("accessSubject"), "read")
|
|
648
|
-
: null;
|
|
647
|
+
const currentProject = conversation.projectId ? await aiProjects.get(conversation.projectId, resourceContext(c), "read") : null;
|
|
649
648
|
if (conversation.projectId && !currentProject) return respond(c, fail(err.notFound("Project")));
|
|
650
649
|
return respond(c, ok(publicConversation(conversation, currentProject?.shortId ?? null)), 201);
|
|
651
650
|
} catch (error) {
|
|
@@ -660,7 +659,7 @@ export const aiRoutes = (() => {
|
|
|
660
659
|
if (ctx instanceof Response) return ctx;
|
|
661
660
|
const conversation = await loadConversation(c, ctx);
|
|
662
661
|
if (!conversation) return notFound(c);
|
|
663
|
-
return respond(c, ok(await conversationDetail(conversation, c
|
|
662
|
+
return respond(c, ok(await conversationDetail(conversation, resourceContext(c))));
|
|
664
663
|
})
|
|
665
664
|
.get(
|
|
666
665
|
"/conversations/:conversationId/submission/:draftRevision",
|
|
@@ -670,7 +669,7 @@ export const aiRoutes = (() => {
|
|
|
670
669
|
if (ctx instanceof Response) return ctx;
|
|
671
670
|
const conversation = await loadConversation(c, ctx);
|
|
672
671
|
if (!conversation) return notFound(c);
|
|
673
|
-
if (conversation.projectId && !(await aiProjects.get(conversation.projectId, c
|
|
672
|
+
if (conversation.projectId && !(await aiProjects.get(conversation.projectId, resourceContext(c), "read"))) return notFound(c);
|
|
674
673
|
const submission = await aiConversations.getDraftSubmission({
|
|
675
674
|
conversationId: conversation.id,
|
|
676
675
|
ownerUserId: ctx.ownerUserId,
|
|
@@ -798,7 +797,7 @@ export const aiRoutes = (() => {
|
|
|
798
797
|
pinned: body.pinned,
|
|
799
798
|
});
|
|
800
799
|
if (!updated) return notFound(c);
|
|
801
|
-
return respond(c, ok(await publicConversationFor(updated, c
|
|
800
|
+
return respond(c, ok(await publicConversationFor(updated, resourceContext(c))));
|
|
802
801
|
})
|
|
803
802
|
.put("/conversations/:conversationId/project", v("json", ConversationProjectInputSchema), async (c) => {
|
|
804
803
|
const ctx = await resolveContext(c);
|
|
@@ -806,7 +805,7 @@ export const aiRoutes = (() => {
|
|
|
806
805
|
const conversation = await loadConversation(c, ctx);
|
|
807
806
|
if (!conversation) return notFound(c);
|
|
808
807
|
const body = c.req.valid("json");
|
|
809
|
-
const project = body.projectId ? await aiProjects.getByShortId(body.projectId, c
|
|
808
|
+
const project = body.projectId ? await aiProjects.getByShortId(body.projectId, resourceContext(c), "read") : null;
|
|
810
809
|
if (body.projectId && !project) return respond(c, fail(err.notFound("Project")));
|
|
811
810
|
const result = await aiConversations.setConversationProject({
|
|
812
811
|
conversationId: conversation.id,
|
|
@@ -821,7 +820,7 @@ export const aiRoutes = (() => {
|
|
|
821
820
|
}
|
|
822
821
|
return notFound(c);
|
|
823
822
|
}
|
|
824
|
-
return respond(c, ok(await publicConversationFor(result.conversation, c
|
|
823
|
+
return respond(c, ok(await publicConversationFor(result.conversation, resourceContext(c))));
|
|
825
824
|
})
|
|
826
825
|
.post("/conversations/:conversationId/pin", async (c) => {
|
|
827
826
|
const ctx = await resolveContext(c);
|
|
@@ -833,7 +832,7 @@ export const aiRoutes = (() => {
|
|
|
833
832
|
ownerUserId: ctx.ownerUserId,
|
|
834
833
|
pinned: true,
|
|
835
834
|
});
|
|
836
|
-
return updated ? respond(c, ok(await publicConversationFor(updated, c
|
|
835
|
+
return updated ? respond(c, ok(await publicConversationFor(updated, resourceContext(c)))) : notFound(c);
|
|
837
836
|
})
|
|
838
837
|
.delete("/conversations/:conversationId/pin", async (c) => {
|
|
839
838
|
const ctx = await resolveContext(c);
|
|
@@ -845,7 +844,7 @@ export const aiRoutes = (() => {
|
|
|
845
844
|
ownerUserId: ctx.ownerUserId,
|
|
846
845
|
pinned: false,
|
|
847
846
|
});
|
|
848
|
-
return updated ? respond(c, ok(await publicConversationFor(updated, c
|
|
847
|
+
return updated ? respond(c, ok(await publicConversationFor(updated, resourceContext(c)))) : notFound(c);
|
|
849
848
|
})
|
|
850
849
|
.put("/conversations/:conversationId/done", v("json", z.object({ done: z.boolean().nullable() })), async (c) => {
|
|
851
850
|
const ctx = await resolveContext(c);
|
|
@@ -861,7 +860,7 @@ export const aiRoutes = (() => {
|
|
|
861
860
|
return result.reason === "active_turn"
|
|
862
861
|
? respond(c, fail(err.conflict("Stop the current response before marking this chat done.")))
|
|
863
862
|
: notFound(c);
|
|
864
|
-
return respond(c, ok(await publicConversationFor(result.conversation, c
|
|
863
|
+
return respond(c, ok(await publicConversationFor(result.conversation, resourceContext(c))));
|
|
865
864
|
})
|
|
866
865
|
.post("/conversations/:conversationId/archive", async (c) => {
|
|
867
866
|
const ctx = await resolveContext(c);
|
|
@@ -911,7 +910,7 @@ export const aiRoutes = (() => {
|
|
|
911
910
|
error: error instanceof Error ? error.message : String(error),
|
|
912
911
|
}),
|
|
913
912
|
);
|
|
914
|
-
return restored ? respond(c, ok(await publicConversationFor(restored, c
|
|
913
|
+
return restored ? respond(c, ok(await publicConversationFor(restored, resourceContext(c)))) : notFound(c);
|
|
915
914
|
})
|
|
916
915
|
.post("/conversations/:conversationId/viewed", async (c) => {
|
|
917
916
|
const ctx = await resolveContext(c);
|
|
@@ -1008,7 +1007,7 @@ export const aiRoutes = (() => {
|
|
|
1008
1007
|
};
|
|
1009
1008
|
});
|
|
1010
1009
|
const { input, message } = aiInputToUserMessage(aiTurnInputToContent({ content: turnContent }));
|
|
1011
|
-
const project = conversation.projectId ? await aiProjects.snapshot(conversation.projectId, c
|
|
1010
|
+
const project = conversation.projectId ? await aiProjects.snapshot(conversation.projectId, resourceContext(c)) : null;
|
|
1012
1011
|
if (conversation.projectId && !project) return respond(c, fail(err.notFound("Project")));
|
|
1013
1012
|
try {
|
|
1014
1013
|
const submission = {
|
|
@@ -1022,7 +1021,7 @@ export const aiRoutes = (() => {
|
|
|
1022
1021
|
locale: getLocale(c),
|
|
1023
1022
|
theme: readThemeFromCookieHeader(c.req.header("cookie")),
|
|
1024
1023
|
timeZone: getTimeZone(c),
|
|
1025
|
-
|
|
1024
|
+
model: body.model ?? project?.defaultModel ?? undefined,
|
|
1026
1025
|
modelPolicy: ctx.modelPolicy,
|
|
1027
1026
|
project: project ?? undefined,
|
|
1028
1027
|
clientToolIds: body.clientToolIds,
|
|
@@ -1043,7 +1042,7 @@ export const aiRoutes = (() => {
|
|
|
1043
1042
|
return respond(c, ok({ queued: true }));
|
|
1044
1043
|
}
|
|
1045
1044
|
const result = await submitAiChatTurn(submission);
|
|
1046
|
-
rememberLastUsedModel(ctx.actor,
|
|
1045
|
+
rememberLastUsedModel(ctx.actor, body.model);
|
|
1047
1046
|
return respond(
|
|
1048
1047
|
c,
|
|
1049
1048
|
ok({
|
|
@@ -1111,13 +1110,13 @@ export const aiRoutes = (() => {
|
|
|
1111
1110
|
? await aiConversations.getTurnRunConfig({ conversationId: conversation.id, turnId: target.loopId })
|
|
1112
1111
|
: null;
|
|
1113
1112
|
const originalProject = originalRunConfig?.kind !== "compact" ? originalRunConfig?.project : undefined;
|
|
1114
|
-
const currentProject = originalProject?.id ? await aiProjects.getByShortId(originalProject.id, c
|
|
1113
|
+
const currentProject = originalProject?.id ? await aiProjects.getByShortId(originalProject.id, resourceContext(c)) : null;
|
|
1115
1114
|
if (originalProject && !currentProject) return respond(c, fail(err.notFound("Project")));
|
|
1116
1115
|
|
|
1117
1116
|
try {
|
|
1118
|
-
const
|
|
1117
|
+
const model = await selectAssistantAiModel(
|
|
1119
1118
|
c.get("accessSubject"),
|
|
1120
|
-
body.
|
|
1119
|
+
body.model ?? originalProject?.defaultModel ?? undefined,
|
|
1121
1120
|
ctx.modelPolicy,
|
|
1122
1121
|
);
|
|
1123
1122
|
if ((await prepareConversationForMessageRetry(conversation.id)) === "busy") {
|
|
@@ -1134,7 +1133,7 @@ export const aiRoutes = (() => {
|
|
|
1134
1133
|
locale: getLocale(c),
|
|
1135
1134
|
theme: readThemeFromCookieHeader(c.req.header("cookie")),
|
|
1136
1135
|
timeZone: getTimeZone(c),
|
|
1137
|
-
|
|
1136
|
+
model,
|
|
1138
1137
|
modelPolicy: ctx.modelPolicy,
|
|
1139
1138
|
systemPrompt,
|
|
1140
1139
|
project: originalProject,
|
|
@@ -1158,7 +1157,7 @@ export const aiRoutes = (() => {
|
|
|
1158
1157
|
}
|
|
1159
1158
|
: undefined,
|
|
1160
1159
|
});
|
|
1161
|
-
rememberLastUsedModel(ctx.actor,
|
|
1160
|
+
rememberLastUsedModel(ctx.actor, body.model);
|
|
1162
1161
|
return respond(
|
|
1163
1162
|
c,
|
|
1164
1163
|
ok({
|
|
@@ -1190,7 +1189,7 @@ export const aiRoutes = (() => {
|
|
|
1190
1189
|
}
|
|
1191
1190
|
|
|
1192
1191
|
const body = c.req.valid("json");
|
|
1193
|
-
if (conversation.projectId && !(await aiProjects.get(conversation.projectId, c
|
|
1192
|
+
if (conversation.projectId && !(await aiProjects.get(conversation.projectId, resourceContext(c), "read"))) {
|
|
1194
1193
|
return respond(c, fail(err.notFound("Project")));
|
|
1195
1194
|
}
|
|
1196
1195
|
const forked = await aiConversations.forkConversation({
|
|
@@ -1199,7 +1198,7 @@ export const aiRoutes = (() => {
|
|
|
1199
1198
|
ownerUserId: ctx.ownerUserId,
|
|
1200
1199
|
title: body.title ?? conversation.title,
|
|
1201
1200
|
});
|
|
1202
|
-
return respond(c, ok(await conversationDetail(forked, c
|
|
1201
|
+
return respond(c, ok(await conversationDetail(forked, resourceContext(c))));
|
|
1203
1202
|
})
|
|
1204
1203
|
.get("/conversations/:conversationId/enrichment", async (c) => {
|
|
1205
1204
|
const ctx = await resolveContext(c);
|
|
@@ -1230,7 +1229,7 @@ export const aiRoutes = (() => {
|
|
|
1230
1229
|
const result = await submitAiCompaction({
|
|
1231
1230
|
conversationId: conversation.id,
|
|
1232
1231
|
actor: ctx.actor,
|
|
1233
|
-
|
|
1232
|
+
model: body.model,
|
|
1234
1233
|
modelPolicy: ctx.modelPolicy,
|
|
1235
1234
|
});
|
|
1236
1235
|
return respond(c, ok({ turn: publicTurn(result.turn, conversation.shortId) }), 201);
|
package/src/ai/runtime.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { type ApprovalDecisionChannel, approvals } from "../services/approvals";
|
|
|
8
8
|
import { logger } from "../services/logging";
|
|
9
9
|
import { superviseRuntimeTask } from "../services/runtime-lifecycle";
|
|
10
10
|
import { coreSettings } from "../services/settings/api";
|
|
11
|
+
import type { AiModelRequest } from "../shared/ai-models";
|
|
11
12
|
import {
|
|
12
13
|
AI_WEBSITE_APPROVAL_TOOL,
|
|
13
14
|
type AiToolApprovalChangeContext,
|
|
@@ -15,16 +16,17 @@ import {
|
|
|
15
16
|
aiTurnAllowsRememberedApprovals,
|
|
16
17
|
rememberAiToolApproval,
|
|
17
18
|
} from "./approvals";
|
|
18
|
-
import { aiChatAccessSubject,
|
|
19
|
+
import { aiChatAccessSubject, selectAssistantAiModel } from "./assistant-models";
|
|
19
20
|
import { startAiDictationRuntime } from "./dictation-runtime";
|
|
20
21
|
import { AiTurnExecutor, type ExecutorConfig } from "./executor";
|
|
21
22
|
import { canonicalizeAiConversationAttachments, snapshotAiConversationFiles } from "./file-context";
|
|
22
23
|
import type { AiLocalClient, AiLocalContext } from "./local-tool-contracts";
|
|
23
24
|
import { drainQueuedMessages } from "./message-queue";
|
|
25
|
+
import { aiUserPrefs } from "./prefs";
|
|
24
26
|
import { AI_TURN_LEASE_MS } from "./protocol";
|
|
25
27
|
import { aiQuotas } from "./quotas";
|
|
26
28
|
import { parseAiResourceMarker } from "./resource-markers";
|
|
27
|
-
import { isAiVisionModelConfigured } from "./settings";
|
|
29
|
+
import { isAiVisionModelConfigured, readAiSettingsState } from "./settings";
|
|
28
30
|
import { aiConversations } from "./store";
|
|
29
31
|
import { publishAiWireEvent } from "./stream";
|
|
30
32
|
import { aiToolAudit } from "./tool-audit";
|
|
@@ -110,7 +112,7 @@ export type SubmitAiChatTurnInput = {
|
|
|
110
112
|
theme?: "light" | "dark";
|
|
111
113
|
timeZone?: string;
|
|
112
114
|
modelPolicy?: AiModelPolicy;
|
|
113
|
-
|
|
115
|
+
model?: AiModelRequest;
|
|
114
116
|
/** Optional instructions that apply only to this turn. */
|
|
115
117
|
systemPrompt?: string;
|
|
116
118
|
project?: AiChatTurnRunConfig["project"];
|
|
@@ -143,21 +145,43 @@ export const prepareAiChatTurn = async (input: SubmitAiChatTurnInput) => {
|
|
|
143
145
|
);
|
|
144
146
|
const canonicalInput = files?.attached.length ? inputMessage.content : input.input;
|
|
145
147
|
const hasImageAttachments = Boolean(files?.attached.some((file) => isAiImageMediaType(file.mediaType)));
|
|
148
|
+
const state = await readAiSettingsState();
|
|
146
149
|
const canInspectAttachedImages =
|
|
147
150
|
input.canInspectAttachedImages ??
|
|
148
|
-
(input.toolSource?.kind === "default" && (await isAiVisionModelConfigured(input.modelPolicy?.allowedDataBoundaries)));
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
input:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
(input.toolSource?.kind === "default" && (await isAiVisionModelConfigured(input.modelPolicy?.allowedDataBoundaries, state)));
|
|
152
|
+
let requested = input.model;
|
|
153
|
+
let previousLabel: string | undefined;
|
|
154
|
+
if (input.assistantChat) {
|
|
155
|
+
const latest = await aiConversations.getLatestTurn({ conversationId: input.conversationId, kind: "chat" });
|
|
156
|
+
const previous = latest ? await aiConversations.getTurnRunConfig({ conversationId: input.conversationId, turnId: latest.id }) : null;
|
|
157
|
+
const inherited = previous?.kind === "chat" ? previous.model : undefined;
|
|
158
|
+
requested ??= inherited;
|
|
159
|
+
if (inherited && "id" in inherited && requested && "id" in requested && requested.id === inherited.id) {
|
|
160
|
+
if (!state.profiles.some((profile) => profile.id === inherited.id)) {
|
|
161
|
+
previousLabel = previous?.kind === "chat" ? (previous.modelLabel ?? inherited.id) : inherited.id;
|
|
162
|
+
const subject = aiChatAccessSubject(input.actor);
|
|
163
|
+
const prefs = subject?.type === "user" ? await aiUserPrefs.get(subject.userId) : null;
|
|
164
|
+
requested = prefs?.selection && "class" in prefs.selection ? prefs.selection : { class: "balanced" };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const model = input.assistantChat
|
|
169
|
+
? await selectAssistantAiModel(aiChatAccessSubject(input.actor), requested, input.modelPolicy, state)
|
|
170
|
+
: requested;
|
|
171
|
+
const { resolved } = await validateAiTurnRequest(
|
|
172
|
+
{
|
|
173
|
+
input: canonicalInput,
|
|
174
|
+
hasImageAttachments,
|
|
175
|
+
canInspectAttachedImages,
|
|
176
|
+
modelPolicy: input.modelPolicy,
|
|
177
|
+
model,
|
|
178
|
+
},
|
|
179
|
+
state,
|
|
180
|
+
);
|
|
159
181
|
const quotaSubject = aiChatAccessSubject(input.actor);
|
|
160
|
-
if (input.assistantChat && quotaSubject) await aiQuotas.assertAllowed(quotaSubject, resolved.profile.id);
|
|
182
|
+
if (input.assistantChat && quotaSubject) await aiQuotas.assertAllowed(quotaSubject, resolved.profile.id, state);
|
|
183
|
+
const modelLabel =
|
|
184
|
+
resolved.profile.label + (resolved.profile.id !== resolved.profile.modelId ? ` · ${resolved.profile.variantLabel}` : "");
|
|
161
185
|
const runConfig: AiChatTurnRunConfig = {
|
|
162
186
|
kind: "chat",
|
|
163
187
|
selectedSkillIds: [
|
|
@@ -177,7 +201,10 @@ export const prepareAiChatTurn = async (input: SubmitAiChatTurnInput) => {
|
|
|
177
201
|
...(input.theme ? { theme: input.theme } : {}),
|
|
178
202
|
...(input.timeZone ? { timeZone: input.timeZone } : {}),
|
|
179
203
|
modelPolicy: input.modelPolicy,
|
|
180
|
-
|
|
204
|
+
model,
|
|
205
|
+
modelResolved: resolved.model,
|
|
206
|
+
modelLabel,
|
|
207
|
+
...(previousLabel ? { modelReplacement: { kind: "model_replaced", previousLabel, nextLabel: modelLabel } } : {}),
|
|
181
208
|
systemPrompt: input.systemPrompt,
|
|
182
209
|
project: input.project,
|
|
183
210
|
files,
|
|
@@ -191,7 +218,7 @@ export const prepareAiChatTurn = async (input: SubmitAiChatTurnInput) => {
|
|
|
191
218
|
|
|
192
219
|
return {
|
|
193
220
|
conversationId: input.conversationId,
|
|
194
|
-
|
|
221
|
+
modelId: resolved.profile.id,
|
|
195
222
|
runConfig,
|
|
196
223
|
userMessage,
|
|
197
224
|
truncateFromSeq: input.truncateFromSeq,
|
|
@@ -244,7 +271,7 @@ export const deliverAiInterChatMessage = async (input: {
|
|
|
244
271
|
};
|
|
245
272
|
const delivered = await aiConversations.deliverInterChatMessage({
|
|
246
273
|
messageId: input.message.id,
|
|
247
|
-
|
|
274
|
+
modelId: resolved.profile.id,
|
|
248
275
|
runConfig,
|
|
249
276
|
userMessage: { role: "user", content: [{ type: "text", text }] },
|
|
250
277
|
sourceHref: input.sourceHref,
|
|
@@ -257,20 +284,21 @@ export type SubmitAiCompactionInput = {
|
|
|
257
284
|
conversationId: string;
|
|
258
285
|
actor?: RequestActor;
|
|
259
286
|
modelPolicy?: AiModelPolicy;
|
|
260
|
-
|
|
287
|
+
model?: AiModelRequest;
|
|
261
288
|
};
|
|
262
289
|
|
|
263
290
|
export const submitAiCompaction = async (input: SubmitAiCompactionInput): Promise<{ turn: AiTurn }> => {
|
|
264
|
-
const { resolved } = await validateAiTurnRequest({ input: "", modelPolicy: input.modelPolicy,
|
|
291
|
+
const { resolved } = await validateAiTurnRequest({ input: "", modelPolicy: input.modelPolicy, model: input.model });
|
|
265
292
|
const runConfig: AiCompactionTurnRunConfig = {
|
|
266
293
|
kind: "compact",
|
|
267
294
|
actor: input.actor,
|
|
268
295
|
modelPolicy: input.modelPolicy,
|
|
269
|
-
|
|
296
|
+
model: { id: resolved.profile.id },
|
|
297
|
+
modelResolved: resolved.model,
|
|
270
298
|
};
|
|
271
299
|
const turn = await aiConversations.createCompactionTurn({
|
|
272
300
|
conversationId: input.conversationId,
|
|
273
|
-
|
|
301
|
+
modelId: resolved.profile.id,
|
|
274
302
|
runConfig,
|
|
275
303
|
});
|
|
276
304
|
await enqueueAiTurn({ conversationId: input.conversationId, turnId: turn.id });
|