@meistrari/chat-nuxt 4.5.0-rc.2 → 4.5.0-rc.3
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 +13 -2
- package/dist/module.json +1 -1
- package/dist/runtime/embed/components/chat-embed-inner.vue +2 -5
- package/dist/runtime/embed/components/chat-embed.vue +1 -0
- package/dist/runtime/embed/composables/harness-adapter.d.ts +0 -1
- package/dist/runtime/embed/types.d.ts +3 -4
- package/dist/runtime/lightweight/embed/composables/model-selection.d.ts +1 -2
- package/dist/runtime/lightweight/embed/composables/model-selection.js +5 -22
- package/dist/runtime/lightweight/messages/composables/chat-model-catalog.d.ts +4 -6
- package/dist/runtime/lightweight/messages/composables/chat-model-catalog.js +5 -52
- package/dist/runtime/lightweight/messages/model-options.d.ts +4 -6
- package/dist/runtime/lightweight/messages/model-options.js +3 -10
- package/dist/runtime/messages/components/chat-model-selector.vue +31 -20
- package/dist/runtime/messages/composables/chat-model-catalog.d.ts +8 -0
- package/dist/runtime/messages/composables/chat-model-catalog.js +9 -0
- package/dist/runtime/messages/composables/chat.js +1 -3
- package/dist/runtime/messages/composables/model-catalog-cache.d.ts +7 -0
- package/dist/runtime/messages/composables/model-catalog-cache.js +81 -0
- package/dist/runtime/messages/model-availability.d.ts +2 -5
- package/dist/runtime/messages/model-availability.js +6 -29
- package/dist/runtime/shared/composables/chat-api.d.ts +1 -0
- package/dist/runtime/shared/composables/chat-api.js +2 -0
- package/dist/runtime/shared/composables/chat-request-context.d.ts +2 -0
- package/dist/runtime/shared/composables/chat-request-context.js +4 -0
- package/dist/runtime/types/schemas/chat/conversations.d.ts +2 -22
- package/dist/runtime/types/schemas/chat/model-catalog.d.ts +28 -0
- package/dist/runtime/types/schemas/chat/model-catalog.js +30 -0
- package/dist/runtime/types/schemas/chat/models.d.ts +3 -12
- package/dist/runtime/types/schemas/chat/models.js +4 -1
- package/dist/runtime/types/schemas/index.d.ts +1 -0
- package/dist/runtime/types/schemas/index.js +1 -0
- package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +1 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,17 @@ The table below is a quick index for reading in-repo. **When you change a prop,
|
|
|
75
75
|
|
|
76
76
|
The embed automatically sets the browser tab title to the active conversation title and synchronizes its ID to `?conversationId=` using router replacement, preserving other query parameters and the URL fragment. Starting a new conversation removes the conversation parameter. Opening or reloading that URL restores the conversation; existing `?conversation=` links are also accepted and converted to `?conversationId=`. Explicit `conversationId` and `initialConversationId` props take precedence over the URL on mount. Without a conversation title, the host application controls the tab title.
|
|
77
77
|
|
|
78
|
+
The model catalog loads in the background and never gates send, retry or model
|
|
79
|
+
persistence. Its in-memory cache is scoped to workspace, agent, branch,
|
|
80
|
+
conversation scope, conversation and harness. Lists remain fresh for five minutes;
|
|
81
|
+
refresh failures retain the last valid list for up to 24 hours. Browser requests have a 30-second deadline including proxying and harness resolution;
|
|
82
|
+
the backend catalog lookup has a three-second timeout. Requests share one pending
|
|
83
|
+
request per key and back off from 30 seconds
|
|
84
|
+
to five minutes on failure. Mounted consumers periodically refresh the cache.
|
|
85
|
+
Reloading the page starts a new cache. Cold Claude pickers use bundled options;
|
|
86
|
+
Lightweight keeps the configured/restored selection or the agent default. Neither
|
|
87
|
+
harness changes the selected model when catalog metadata arrives.
|
|
88
|
+
|
|
78
89
|
### `<MeistrariChatEmbed>` props
|
|
79
90
|
|
|
80
91
|
Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload types are importable from the package root or `@meistrari/chat-nuxt/types/embed`.
|
|
@@ -88,8 +99,8 @@ Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload
|
|
|
88
99
|
| `initialConversationId` | `string \| null` | `null` | Conversation to open once on mount when `conversationId` is uncontrolled |
|
|
89
100
|
| `conversationScope` | `string \| null` | `null` | Isolate conversation history by technical scope within the current workspace and runtime. Scoped embeds only see same-scope conversations; values are trimmed, blank becomes `null`, and the server accepts 1-200 chars from `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `/`, `-` |
|
|
90
101
|
| `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter: every conversation in scope, or only the current user's |
|
|
91
|
-
| `availableModels` | `AvailableChatModels` |
|
|
92
|
-
| `defaultModel` | `ChatModel` | Package default | Initial model for untouched drafts. Explicit selections and existing conversations take precedence; `availableModels`
|
|
102
|
+
| `availableModels` | `AvailableChatModels` | Harness catalog | Visual filter and ordering for catalog options. Unknown ids are omitted; if no ids match, the full catalog is shown. Does not change defaults, restored selections or execution. The Agent validates availability |
|
|
103
|
+
| `defaultModel` | `ChatModel` | Package default | Initial model for untouched drafts. Explicit selections and existing conversations take precedence; `availableModels` only filters the selector |
|
|
93
104
|
| `defaultReasoningEffort` | `ChatReasoningEffort` | Automatic (`null`) | Initial reasoning effort for untouched drafts. Explicit user choices (including automatic) take precedence |
|
|
94
105
|
| `conversationCreatorFilter` | `'all' \| 'mine'` | — | Controlled sidebar creator filter; use with `v-model:conversation-creator-filter` when the host changes it at runtime |
|
|
95
106
|
| `hideConversationCreatorFilter` | `boolean` | `false` | Hide the creator selector without changing the active filter |
|
package/dist/module.json
CHANGED
|
@@ -24,8 +24,7 @@ import {
|
|
|
24
24
|
} from "../../messages/composables/chat";
|
|
25
25
|
import {
|
|
26
26
|
ensureConversationUsesSelectedModel,
|
|
27
|
-
MODEL_UPDATE_FAILED_MESSAGE
|
|
28
|
-
resolveChatModelSelection
|
|
27
|
+
MODEL_UPDATE_FAILED_MESSAGE
|
|
29
28
|
} from "../../messages/model-availability";
|
|
30
29
|
import { useChatAction } from "../../messages/composables/chat-action";
|
|
31
30
|
import { useChatApi } from "../../shared/composables/chat-api";
|
|
@@ -291,7 +290,7 @@ async function waitForPendingReasoningEffortUpdate() {
|
|
|
291
290
|
}
|
|
292
291
|
}
|
|
293
292
|
function resolveSelectedModel(value) {
|
|
294
|
-
return nativeModels ? nativeModels.resolve(value) :
|
|
293
|
+
return nativeModels ? nativeModels.resolve(value) : value;
|
|
295
294
|
}
|
|
296
295
|
const selectedModel = computed({
|
|
297
296
|
get: () => resolveSelectedModel(
|
|
@@ -581,7 +580,6 @@ async function dispatchMessage(outbound, files, resolvedAgentInputs) {
|
|
|
581
580
|
return false;
|
|
582
581
|
let claimedWakeSessionId;
|
|
583
582
|
const sent = await sendMessage(outbound, files.length > 0 ? files : void 0, resolvedAgentInputs, async (signal) => {
|
|
584
|
-
await nativeModels?.ensureReady();
|
|
585
583
|
if (!activeConversationId.value || !currentConversation.value) {
|
|
586
584
|
const conversation2 = await createConversation({
|
|
587
585
|
model: selectedModel.value,
|
|
@@ -669,7 +667,6 @@ async function handleCancel() {
|
|
|
669
667
|
}
|
|
670
668
|
async function handleRetry(messageId) {
|
|
671
669
|
await retryMessage(messageId, async () => {
|
|
672
|
-
await nativeModels?.ensureReady();
|
|
673
670
|
await waitForPendingModelUpdate();
|
|
674
671
|
await waitForPendingReasoningEffortUpdate();
|
|
675
672
|
const conversation = currentConversation.value;
|
|
@@ -102,6 +102,7 @@ provideEmbedConfig({
|
|
|
102
102
|
messageFeedback: computed(() => props.messageFeedback)
|
|
103
103
|
}, { syncGlobal: !parentEmbedConfig });
|
|
104
104
|
provideChatRequestContext({
|
|
105
|
+
conversationId: selectedConversationId,
|
|
105
106
|
harness,
|
|
106
107
|
workspaceId,
|
|
107
108
|
telaAgentId: normalizedTelaAgentId,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { useChat } from '../../messages/composables/chat.js';
|
|
2
2
|
type ChatModelPolicy = {
|
|
3
|
-
ensureReady: () => Promise<void>;
|
|
4
3
|
resolve: (value: string | null) => string | null;
|
|
5
4
|
ensureSelectedModel: (current: string | null, selected: string | null, persist: (value: string | null) => Promise<boolean>) => Promise<void>;
|
|
6
5
|
};
|
|
@@ -86,14 +86,13 @@ export type ChatEmbedSharedProps = {
|
|
|
86
86
|
*/
|
|
87
87
|
defaultConversationCreatorFilter?: ConversationCreatorFilter;
|
|
88
88
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
89
|
+
* Visual filter and ordering for the Agent catalog. If no ids match, the full
|
|
90
|
+
* catalog is shown. Does not change defaults, restored selections or execution;
|
|
91
|
+
* the Agent validates model availability.
|
|
92
92
|
*/
|
|
93
93
|
availableModels?: AvailableChatModels;
|
|
94
94
|
/**
|
|
95
95
|
* Initial model for untouched drafts. Existing conversations and explicit selections take precedence.
|
|
96
|
-
* When excluded by availableModels, the first allowed model is used.
|
|
97
96
|
*/
|
|
98
97
|
defaultModel?: string;
|
|
99
98
|
/**
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export declare function useLightweightModelSelection(): {
|
|
2
|
-
|
|
3
|
-
resolve: (selection: string | null) => any;
|
|
2
|
+
resolve: (selection: string | null) => string | null;
|
|
4
3
|
ensureSelectedModel: (current: string | null, selected: string | null, persist: (value: string | null) => Promise<boolean>) => Promise<void>;
|
|
5
4
|
};
|
|
@@ -1,29 +1,12 @@
|
|
|
1
|
-
import { useEmbedConfig } from "../../../embed/composables/embed-config.js";
|
|
2
1
|
import { useChatModelCatalog } from "../../messages/composables/chat-model-catalog.js";
|
|
3
|
-
import { ensureConversationUsesSelectedModel
|
|
2
|
+
import { ensureConversationUsesSelectedModel } from "../../../messages/model-availability.js";
|
|
4
3
|
export function useLightweightModelSelection() {
|
|
5
|
-
const
|
|
6
|
-
const { scopeKey, models, defaultModel, isLoaded, load } = useChatModelCatalog();
|
|
7
|
-
let ready = Promise.resolve();
|
|
8
|
-
const failed = ref(false);
|
|
4
|
+
const { scopeKey, load } = useChatModelCatalog();
|
|
9
5
|
watch(scopeKey, () => {
|
|
10
|
-
|
|
11
|
-
failed.value = false;
|
|
12
|
-
ready = load().catch(() => {
|
|
13
|
-
if (scopeKey.value === scope)
|
|
14
|
-
failed.value = true;
|
|
15
|
-
});
|
|
6
|
+
void load();
|
|
16
7
|
}, { immediate: true });
|
|
17
|
-
const available = computed(() => models.value.length ? resolveAvailableChatModels(embedConfig?.availableModels.value, models.value.map((model) => model.id)) : []);
|
|
18
|
-
const fallback = computed(() => available.value.includes(defaultModel.value ?? "") ? defaultModel.value : available.value[0] ?? null);
|
|
19
|
-
async function ensureReady() {
|
|
20
|
-
await ready;
|
|
21
|
-
if (failed.value || !isLoaded.value || !models.value.length)
|
|
22
|
-
throw new Error("N\xE3o foi poss\xEDvel carregar os modelos dispon\xEDveis neste workspace");
|
|
23
|
-
}
|
|
24
8
|
return {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ensureSelectedModel: (current, selected, persist) => ensureConversationUsesSelectedModel(current, selected, persist, available.value)
|
|
9
|
+
resolve: (selection) => selection,
|
|
10
|
+
ensureSelectedModel: (current, selected, persist) => ensureConversationUsesSelectedModel(current, selected, persist)
|
|
28
11
|
};
|
|
29
12
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
export declare function useChatModelCatalog(): {
|
|
2
|
-
scopeKey: any;
|
|
3
2
|
models: any;
|
|
4
3
|
defaultModel: any;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}) => Promise<void>;
|
|
4
|
+
scopeKey: Readonly<import("vue").Ref<string, string>>;
|
|
5
|
+
isLoaded: Readonly<import("vue").Ref<boolean, boolean>>;
|
|
6
|
+
isLoading: Readonly<import("vue").Ref<any, any>>;
|
|
7
|
+
load: () => Promise<void>;
|
|
10
8
|
};
|
|
@@ -1,55 +1,8 @@
|
|
|
1
1
|
import { chatModelsResponseSchema } from "../../../types/schemas/chat/lightweight-models.js";
|
|
2
|
-
import {
|
|
3
|
-
const pendingLoadsByCatalogState = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
import { useModelCatalogCache } from "../../../messages/composables/model-catalog-cache.js";
|
|
4
3
|
export function useChatModelCatalog() {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
let pendingLoads = pendingLoadsByCatalogState.get(catalogs);
|
|
10
|
-
if (!pendingLoads) {
|
|
11
|
-
pendingLoads = /* @__PURE__ */ new Map();
|
|
12
|
-
pendingLoadsByCatalogState.set(catalogs, pendingLoads);
|
|
13
|
-
}
|
|
14
|
-
const catalogKey = computed(
|
|
15
|
-
() => chatApi.withChatHeaders().headers?.["x-chat-workspace-id"] ?? "__default__"
|
|
16
|
-
);
|
|
17
|
-
const models = computed(() => (catalogs.value[catalogKey.value] ?? []).filter((model) => model.status === "available"));
|
|
18
|
-
const isLoaded = computed(() => loadedCatalogs.value[catalogKey.value] ?? false);
|
|
19
|
-
const isLoading = computed(() => loadingCatalogs.value[catalogKey.value] ?? false);
|
|
20
|
-
const defaultModel = computed(
|
|
21
|
-
() => models.value.find((model) => model.isDefault)?.id ?? models.value[0]?.id ?? null
|
|
22
|
-
);
|
|
23
|
-
async function load(options = {}) {
|
|
24
|
-
const requestOptions = chatApi.withChatHeaders();
|
|
25
|
-
const key = requestOptions.headers?.["x-chat-workspace-id"] ?? "__default__";
|
|
26
|
-
const pending = pendingLoads.get(key);
|
|
27
|
-
if (pending)
|
|
28
|
-
return pending;
|
|
29
|
-
if (loadedCatalogs.value[key] && !options.force)
|
|
30
|
-
return;
|
|
31
|
-
loadingCatalogs.value = { ...loadingCatalogs.value, [key]: true };
|
|
32
|
-
const request = Promise.resolve().then(async () => {
|
|
33
|
-
const response = await $fetch(chatApi.path("/models"), requestOptions);
|
|
34
|
-
catalogs.value = {
|
|
35
|
-
...catalogs.value,
|
|
36
|
-
[key]: chatModelsResponseSchema.parse(response).models
|
|
37
|
-
};
|
|
38
|
-
loadedCatalogs.value = { ...loadedCatalogs.value, [key]: true };
|
|
39
|
-
}).finally(() => {
|
|
40
|
-
loadingCatalogs.value = { ...loadingCatalogs.value, [key]: false };
|
|
41
|
-
if (pendingLoads.get(key) === request)
|
|
42
|
-
pendingLoads.delete(key);
|
|
43
|
-
});
|
|
44
|
-
pendingLoads.set(key, request);
|
|
45
|
-
return request;
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
scopeKey: readonly(catalogKey),
|
|
49
|
-
models: readonly(models),
|
|
50
|
-
defaultModel,
|
|
51
|
-
isLoaded: readonly(isLoaded),
|
|
52
|
-
isLoading: readonly(isLoading),
|
|
53
|
-
load
|
|
54
|
-
};
|
|
4
|
+
const catalog = useModelCatalogCache("lightweight", (response) => chatModelsResponseSchema.parse(response).models, []);
|
|
5
|
+
const models = computed(() => catalog.models.value.filter((model) => model.status === "available"));
|
|
6
|
+
const defaultModel = computed(() => models.value.find((model) => model.isDefault)?.id ?? models.value[0]?.id ?? null);
|
|
7
|
+
return { ...catalog, models: readonly(models), defaultModel };
|
|
55
8
|
}
|
|
@@ -7,6 +7,10 @@ type BuildChatModelOptionsInput = {
|
|
|
7
7
|
providerIcons: Readonly<Record<string, Component>>;
|
|
8
8
|
};
|
|
9
9
|
export declare function buildChatModelOptions(input: BuildChatModelOptionsInput): ({
|
|
10
|
+
value: string;
|
|
11
|
+
label: string;
|
|
12
|
+
tabs: string[];
|
|
13
|
+
} | {
|
|
10
14
|
isMultiModal: any;
|
|
11
15
|
tabs: string[];
|
|
12
16
|
maxOutputTokens?: any;
|
|
@@ -17,11 +21,5 @@ export declare function buildChatModelOptions(input: BuildChatModelOptionsInput)
|
|
|
17
21
|
icon: Component | undefined;
|
|
18
22
|
cost: any;
|
|
19
23
|
maxInputTokens: any;
|
|
20
|
-
} | {
|
|
21
|
-
value: string;
|
|
22
|
-
label: string;
|
|
23
|
-
description: string;
|
|
24
|
-
group: string;
|
|
25
|
-
tabs: string[];
|
|
26
24
|
})[];
|
|
27
25
|
export {};
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { resolveAvailableChatModels } from "../../messages/model-availability.js";
|
|
2
2
|
export function buildChatModelOptions(input) {
|
|
3
|
-
|
|
4
|
-
return [];
|
|
5
|
-
const availableModels = resolveAvailableChatModels(
|
|
6
|
-
input.availableModels,
|
|
7
|
-
input.models.map((candidate) => candidate.id)
|
|
8
|
-
);
|
|
3
|
+
const availableModels = resolveAvailableChatModels(input.availableModels, input.models.map((candidate) => candidate.id));
|
|
9
4
|
const options = availableModels.map((modelId) => {
|
|
10
5
|
const model = input.models.find((candidate) => candidate.id === modelId);
|
|
11
6
|
if (!model)
|
|
12
|
-
|
|
7
|
+
return { value: modelId, label: modelId, tabs: ["all"] };
|
|
13
8
|
const isMultiModal = model.inputModalities.some((modality) => modality !== "text");
|
|
14
9
|
return {
|
|
15
10
|
value: model.id,
|
|
@@ -32,9 +27,7 @@ export function buildChatModelOptions(input) {
|
|
|
32
27
|
return options;
|
|
33
28
|
return [{
|
|
34
29
|
value: input.selectedModel,
|
|
35
|
-
label:
|
|
36
|
-
description: "Selecione um modelo dispon\xEDvel antes de enviar uma mensagem.",
|
|
37
|
-
group: "Indispon\xEDvel",
|
|
30
|
+
label: input.selectedModel,
|
|
38
31
|
tabs: ["all"]
|
|
39
32
|
}, ...options];
|
|
40
33
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { chatModelTabs } from "../../types/schemas/chat/model-catalog.js";
|
|
3
3
|
import { useEmbedConfig } from "../../embed/composables/embed-config";
|
|
4
|
+
import { useChatModelCatalog } from "../composables/chat-model-catalog";
|
|
4
5
|
import { useChatRequestContext } from "../../shared/composables/chat-request-context";
|
|
5
|
-
import { useChatModelCatalog } from "../../lightweight/messages/composables/chat-model-catalog";
|
|
6
|
+
import { useChatModelCatalog as useLightweightModelCatalog } from "../../lightweight/messages/composables/chat-model-catalog";
|
|
6
7
|
import { buildChatModelOptions } from "../../lightweight/messages/model-options";
|
|
7
8
|
import { resolveAvailableChatModels } from "../model-availability";
|
|
8
9
|
import TelaChatIconsAnthropic from "@meistrari/tela-build/components/tela/chat/icons/anthropic.vue";
|
|
@@ -13,12 +14,29 @@ defineProps({
|
|
|
13
14
|
});
|
|
14
15
|
const model = defineModel({ type: [String, null], ...{ default: null } });
|
|
15
16
|
const embedConfig = useEmbedConfig();
|
|
16
|
-
const
|
|
17
|
+
const isLightweight = useChatRequestContext()?.harness?.value === "lightweight";
|
|
18
|
+
const lightweightCatalog = isLightweight ? useLightweightModelCatalog() : null;
|
|
19
|
+
const catalog = isLightweight ? null : useChatModelCatalog();
|
|
20
|
+
const activeCatalog = lightweightCatalog ?? catalog;
|
|
17
21
|
const providerIcons = {
|
|
18
22
|
Anthropic: TelaChatIconsAnthropic,
|
|
19
23
|
OpenAI: TelaChatIconsOpenai,
|
|
20
24
|
Google: TelaChatIconsGemini
|
|
21
25
|
};
|
|
26
|
+
function toOption(entry) {
|
|
27
|
+
return {
|
|
28
|
+
value: entry.id,
|
|
29
|
+
label: entry.label,
|
|
30
|
+
description: entry.description ?? void 0,
|
|
31
|
+
group: entry.provider,
|
|
32
|
+
icon: providerIcons[entry.provider],
|
|
33
|
+
cost: entry.cost,
|
|
34
|
+
maxInputTokens: entry.maxInputTokens,
|
|
35
|
+
maxOutputTokens: entry.maxOutputTokens ?? void 0,
|
|
36
|
+
isMultiModal: entry.isMultiModal,
|
|
37
|
+
tabs: chatModelTabs(entry)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
22
40
|
const options = computed(() => {
|
|
23
41
|
if (lightweightCatalog) {
|
|
24
42
|
return buildChatModelOptions({
|
|
@@ -28,23 +46,13 @@ const options = computed(() => {
|
|
|
28
46
|
providerIcons
|
|
29
47
|
});
|
|
30
48
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
label: option.label,
|
|
39
|
-
description: option.description,
|
|
40
|
-
group: option.provider,
|
|
41
|
-
icon: providerIcons[option.provider],
|
|
42
|
-
cost: option.cost,
|
|
43
|
-
maxInputTokens: option.maxInputTokens,
|
|
44
|
-
maxOutputTokens: option.maxOutputTokens,
|
|
45
|
-
isMultiModal: option.isMultiModal,
|
|
46
|
-
tabs: [...option.tabs]
|
|
47
|
-
};
|
|
49
|
+
if (!catalog)
|
|
50
|
+
return [];
|
|
51
|
+
const availableModels = resolveAvailableChatModels(embedConfig?.availableModels.value, catalog.modelIds.value);
|
|
52
|
+
const optionIds = model.value && !availableModels.includes(model.value) ? [model.value, ...availableModels] : availableModels;
|
|
53
|
+
return optionIds.map((id) => {
|
|
54
|
+
const entry = catalog.models.value.find((candidate) => candidate.id === id);
|
|
55
|
+
return entry ? toOption(entry) : { value: id, label: id, tabs: ["all"] };
|
|
48
56
|
});
|
|
49
57
|
});
|
|
50
58
|
const tabLabels = {
|
|
@@ -53,6 +61,9 @@ const tabLabels = {
|
|
|
53
61
|
cheap: "Econ\xF4micos",
|
|
54
62
|
multimodal: "Multimodal"
|
|
55
63
|
};
|
|
64
|
+
watch(activeCatalog.scopeKey, () => {
|
|
65
|
+
void activeCatalog.load();
|
|
66
|
+
}, { immediate: true });
|
|
56
67
|
</script>
|
|
57
68
|
|
|
58
69
|
<template>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function useChatModelCatalog(): {
|
|
2
|
+
modelIds: any;
|
|
3
|
+
scopeKey: Readonly<import("vue").Ref<string, string>>;
|
|
4
|
+
models: Readonly<import("vue").Ref<any, any>>;
|
|
5
|
+
isLoaded: Readonly<import("vue").Ref<boolean, boolean>>;
|
|
6
|
+
isLoading: Readonly<import("vue").Ref<any, any>>;
|
|
7
|
+
load: () => Promise<void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { chatModelCatalogResponseSchema, fallbackChatModelCatalog } from "../../types/schemas/chat/model-catalog.js";
|
|
2
|
+
import { useModelCatalogCache } from "./model-catalog-cache.js";
|
|
3
|
+
export function useChatModelCatalog() {
|
|
4
|
+
const catalog = useModelCatalogCache("claude", (response) => {
|
|
5
|
+
const parsed = chatModelCatalogResponseSchema.parse(response);
|
|
6
|
+
return parsed.catalogAvailable ? parsed.models : null;
|
|
7
|
+
}, fallbackChatModelCatalog);
|
|
8
|
+
return { ...catalog, modelIds: computed(() => catalog.models.value.map((model) => model.id)) };
|
|
9
|
+
}
|
|
@@ -420,9 +420,7 @@ export function useChat(options = {}, adapter = {}) {
|
|
|
420
420
|
const buckets = pendingModelBuckets.value;
|
|
421
421
|
if (chatScope.value in buckets)
|
|
422
422
|
return buckets[chatScope.value] ?? null;
|
|
423
|
-
|
|
424
|
-
const allowed = embedConfig?.availableModels?.value;
|
|
425
|
-
return model && allowed?.length && !allowed.includes(model) ? allowed[0] : model;
|
|
423
|
+
return embedConfig?.defaultModel?.value ?? (adapter.defaultModel === void 0 ? defaultChatModel : adapter.defaultModel);
|
|
426
424
|
},
|
|
427
425
|
set: (value) => {
|
|
428
426
|
pendingModelBuckets.value = {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function useModelCatalogCache<T>(harness: 'claude' | 'lightweight', parse: (response: unknown) => T[] | null, fallback: readonly T[]): {
|
|
2
|
+
scopeKey: Readonly<import("vue").Ref<string, string>>;
|
|
3
|
+
models: Readonly<import("vue").Ref<any, any>>;
|
|
4
|
+
isLoaded: Readonly<import("vue").Ref<boolean, boolean>>;
|
|
5
|
+
isLoading: Readonly<import("vue").Ref<any, any>>;
|
|
6
|
+
load: () => Promise<void>;
|
|
7
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { computed, getCurrentInstance, onMounted, onUnmounted, readonly } from "vue";
|
|
2
|
+
import { useChatApi } from "../../shared/composables/chat-api.js";
|
|
3
|
+
const FRESH_MS = 5 * 6e4;
|
|
4
|
+
const RETAIN_MS = 24 * 60 * 6e4;
|
|
5
|
+
const pendingByState = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
export function useModelCatalogCache(harness, parse, fallback) {
|
|
7
|
+
const chatApi = useChatApi();
|
|
8
|
+
const entries = useState(`chat-model-catalog-${harness}`, () => ({}));
|
|
9
|
+
const loading = useState(`chat-model-catalog-${harness}-loading`, () => ({}));
|
|
10
|
+
let pending = pendingByState.get(entries.value);
|
|
11
|
+
if (!pending) {
|
|
12
|
+
pending = /* @__PURE__ */ new Map();
|
|
13
|
+
pendingByState.set(entries.value, pending);
|
|
14
|
+
}
|
|
15
|
+
function requestContext() {
|
|
16
|
+
const conversationId = chatApi.conversationId?.value;
|
|
17
|
+
const options = chatApi.withChatHeaders({
|
|
18
|
+
...conversationId ? { query: { conversationId } } : {},
|
|
19
|
+
// This deadline also covers proxying and harness resolution before the upstream catalog timeout starts.
|
|
20
|
+
timeout: 3e4,
|
|
21
|
+
retry: 0
|
|
22
|
+
});
|
|
23
|
+
const headers = options.headers;
|
|
24
|
+
const key = JSON.stringify([
|
|
25
|
+
harness,
|
|
26
|
+
headers?.["x-chat-workspace-id"],
|
|
27
|
+
headers?.["x-chat-tela-agent-id"],
|
|
28
|
+
headers?.["x-chat-tela-agent-branch"],
|
|
29
|
+
headers?.["x-chat-conversation-scope"],
|
|
30
|
+
conversationId
|
|
31
|
+
]);
|
|
32
|
+
return { key, options };
|
|
33
|
+
}
|
|
34
|
+
const scopeKey = computed(() => requestContext().key);
|
|
35
|
+
const models = computed(() => entries.value[scopeKey.value]?.models ?? fallback);
|
|
36
|
+
const isLoaded = computed(() => Boolean(entries.value[scopeKey.value]?.models));
|
|
37
|
+
const isLoading = computed(() => loading.value[scopeKey.value] ?? false);
|
|
38
|
+
async function load() {
|
|
39
|
+
const { key, options } = requestContext();
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
for (const [entryKey, entry] of Object.entries(entries.value)) {
|
|
42
|
+
if (now - (entry.updatedAt ?? entry.attemptedAt) >= RETAIN_MS)
|
|
43
|
+
delete entries.value[entryKey];
|
|
44
|
+
}
|
|
45
|
+
const cached = entries.value[key];
|
|
46
|
+
if (cached?.updatedAt !== void 0 && now - cached.updatedAt < FRESH_MS)
|
|
47
|
+
return;
|
|
48
|
+
if (pending.has(key))
|
|
49
|
+
return pending.get(key);
|
|
50
|
+
if (cached && now < cached.retryAt)
|
|
51
|
+
return;
|
|
52
|
+
loading.value[key] = true;
|
|
53
|
+
const request = Promise.resolve().then(async () => {
|
|
54
|
+
try {
|
|
55
|
+
const result = parse(await $fetch(chatApi.path("/models"), options));
|
|
56
|
+
if (!result?.length)
|
|
57
|
+
throw new Error("Model catalog unavailable");
|
|
58
|
+
entries.value[key] = { models: result, updatedAt: Date.now(), attemptedAt: Date.now(), retryAt: 0, failures: 0 };
|
|
59
|
+
} catch {
|
|
60
|
+
const failures = (cached?.failures ?? 0) + 1;
|
|
61
|
+
const retained = cached?.updatedAt !== void 0 && Date.now() - cached.updatedAt < RETAIN_MS ? cached : void 0;
|
|
62
|
+
entries.value[key] = { ...retained, failures, attemptedAt: Date.now(), retryAt: Date.now() + Math.min(3e4 * 2 ** (failures - 1), FRESH_MS) };
|
|
63
|
+
} finally {
|
|
64
|
+
delete loading.value[key];
|
|
65
|
+
pending.delete(key);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
pending.set(key, request);
|
|
69
|
+
return request;
|
|
70
|
+
}
|
|
71
|
+
if (getCurrentInstance()) {
|
|
72
|
+
let refresh;
|
|
73
|
+
onMounted(() => {
|
|
74
|
+
refresh = setInterval(() => {
|
|
75
|
+
void load();
|
|
76
|
+
}, FRESH_MS);
|
|
77
|
+
});
|
|
78
|
+
onUnmounted(() => clearInterval(refresh));
|
|
79
|
+
}
|
|
80
|
+
return { scopeKey: readonly(scopeKey), models: readonly(models), isLoaded: readonly(isLoaded), isLoading: readonly(isLoading), load };
|
|
81
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import type { ChatModel } from '../types/schemas/chat/models.js';
|
|
2
2
|
export type AvailableChatModels = readonly [ChatModel, ...ChatModel[]];
|
|
3
3
|
export declare const MODEL_UPDATE_FAILED_MESSAGE = "N\u00E3o foi poss\u00EDvel atualizar o modelo da conversa";
|
|
4
|
-
export declare
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function resolveAvailableChatModels(availableModels: readonly string[] | undefined, catalogModels: readonly string[]): readonly string[];
|
|
7
|
-
export declare function resolveChatModelSelection(selectedModel: string | null, availableModels?: readonly string[]): string | null;
|
|
8
|
-
export declare function ensureConversationUsesSelectedModel(conversationModel: string | null, selectedModel: string | null, updateModel: (model: string | null) => Promise<boolean>, availableModels?: readonly string[]): Promise<void>;
|
|
4
|
+
export declare function resolveAvailableChatModels(availableModels?: readonly string[], catalogModels?: readonly string[]): readonly string[];
|
|
5
|
+
export declare function ensureConversationUsesSelectedModel(conversationModel: string | null, selectedModel: string | null, updateModel: (model: string | null) => Promise<boolean>): Promise<void>;
|
|
@@ -1,36 +1,13 @@
|
|
|
1
1
|
import { chatModelIds } from "../types/schemas/chat/models.js";
|
|
2
2
|
export const MODEL_UPDATE_FAILED_MESSAGE = "N\xE3o foi poss\xEDvel atualizar o modelo da conversa";
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
const catalog = catalogModels ?? chatModelIds;
|
|
6
|
-
if (catalog.length === 0)
|
|
7
|
-
throw new Error("Agent API model catalog must contain at least one model");
|
|
3
|
+
export function resolveAvailableChatModels(availableModels, catalogModels = chatModelIds) {
|
|
4
|
+
const catalog = [...new Set(catalogModels)];
|
|
8
5
|
if (availableModels === void 0)
|
|
9
|
-
return
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return offeredModels.length ? offeredModels : [...new Set(catalog)];
|
|
13
|
-
}
|
|
14
|
-
if (availableModels.length === 0)
|
|
15
|
-
throw new Error("availableModels must contain at least one model");
|
|
16
|
-
const uniqueModels = [];
|
|
17
|
-
for (const model of availableModels) {
|
|
18
|
-
if (!catalog.includes(model))
|
|
19
|
-
throw new Error(`${model} is not a supported chat model`);
|
|
20
|
-
if (!uniqueModels.includes(model))
|
|
21
|
-
uniqueModels.push(model);
|
|
22
|
-
}
|
|
23
|
-
return uniqueModels;
|
|
6
|
+
return catalog;
|
|
7
|
+
const offeredModels = [...new Set(availableModels.filter((model) => catalog.includes(model)))];
|
|
8
|
+
return offeredModels.length ? offeredModels : catalog;
|
|
24
9
|
}
|
|
25
|
-
export function
|
|
26
|
-
if (availableModels === void 0)
|
|
27
|
-
return selectedModel;
|
|
28
|
-
const resolvedModels = resolveAvailableChatModels(availableModels);
|
|
29
|
-
return selectedModel && resolvedModels.includes(selectedModel) ? selectedModel : resolvedModels[0];
|
|
30
|
-
}
|
|
31
|
-
export async function ensureConversationUsesSelectedModel(conversationModel, selectedModel, updateModel, availableModels) {
|
|
32
|
-
if (selectedModel && availableModels && !availableModels.includes(selectedModel))
|
|
33
|
-
throw new Error(MODEL_UNAVAILABLE_MESSAGE);
|
|
10
|
+
export async function ensureConversationUsesSelectedModel(conversationModel, selectedModel, updateModel) {
|
|
34
11
|
if (conversationModel === selectedModel)
|
|
35
12
|
return;
|
|
36
13
|
if (!await updateModel(selectedModel))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare function useChatApi(): {
|
|
2
2
|
path: (routePath: string) => string;
|
|
3
|
+
conversationId: import("vue").ComputedRef<string | null>;
|
|
3
4
|
runtimePath: (routePath: string) => string;
|
|
4
5
|
conversationV2Enabled: boolean;
|
|
5
6
|
withChatHeaders: <const T extends Record<string, any>>(options?: T) => T & {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
1
2
|
import { useChatAuth } from "#chat-auth";
|
|
2
3
|
import { useChatRequestContext } from "./chat-request-context.js";
|
|
3
4
|
export function useChatApi() {
|
|
@@ -38,6 +39,7 @@ export function useChatApi() {
|
|
|
38
39
|
}
|
|
39
40
|
return {
|
|
40
41
|
path,
|
|
42
|
+
conversationId: computed(() => requestContext?.conversationId?.value ?? null),
|
|
41
43
|
runtimePath: (routePath) => `/api/v2${routePath}`,
|
|
42
44
|
conversationV2Enabled: true,
|
|
43
45
|
withChatHeaders
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ChatHarness } from '../../types/schemas/chat/chat-config.js';
|
|
2
2
|
import type { MaybeRefOrGetter, Ref } from 'vue';
|
|
3
3
|
export type ChatRequestContext = {
|
|
4
|
+
conversationId?: Ref<string | null>;
|
|
4
5
|
harness?: Ref<ChatHarness | null>;
|
|
5
6
|
workspaceId: Ref<string>;
|
|
6
7
|
telaAgentId: Ref<string | null>;
|
|
@@ -8,6 +9,7 @@ export type ChatRequestContext = {
|
|
|
8
9
|
conversationScope: Ref<string | null>;
|
|
9
10
|
};
|
|
10
11
|
type ChatRequestContextInput = {
|
|
12
|
+
conversationId?: MaybeRefOrGetter<string | null | undefined>;
|
|
11
13
|
harness?: MaybeRefOrGetter<ChatHarness | null>;
|
|
12
14
|
workspaceId: MaybeRefOrGetter<string | null | undefined>;
|
|
13
15
|
telaAgentId?: MaybeRefOrGetter<string | null | undefined>;
|
|
@@ -5,6 +5,7 @@ function normalizeOptionalHeaderValue(value) {
|
|
|
5
5
|
}
|
|
6
6
|
function useGlobalChatRequestContextState() {
|
|
7
7
|
return {
|
|
8
|
+
conversationId: useState("chat-request-context-conversation-id", () => null),
|
|
8
9
|
harness: useState("chat-request-context-harness", () => null),
|
|
9
10
|
provided: useState("chat-request-context-provided", () => false),
|
|
10
11
|
workspaceId: useState("chat-request-context-workspace-id", () => ""),
|
|
@@ -15,6 +16,7 @@ function useGlobalChatRequestContextState() {
|
|
|
15
16
|
}
|
|
16
17
|
export function provideChatRequestContext(input, options = {}) {
|
|
17
18
|
const context = {
|
|
19
|
+
conversationId: computed(() => normalizeOptionalHeaderValue(toValue(input.conversationId))),
|
|
18
20
|
harness: computed(() => toValue(input.harness) ?? null),
|
|
19
21
|
workspaceId: computed(() => normalizeOptionalHeaderValue(toValue(input.workspaceId)) ?? ""),
|
|
20
22
|
telaAgentId: computed(() => normalizeOptionalHeaderValue(toValue(input.telaAgentId))),
|
|
@@ -24,6 +26,7 @@ export function provideChatRequestContext(input, options = {}) {
|
|
|
24
26
|
const globalContext = useGlobalChatRequestContextState();
|
|
25
27
|
if (options.syncGlobal ?? true) {
|
|
26
28
|
watchEffect(() => {
|
|
29
|
+
globalContext.conversationId.value = context.conversationId.value;
|
|
27
30
|
globalContext.harness.value = context.harness.value;
|
|
28
31
|
globalContext.provided.value = true;
|
|
29
32
|
globalContext.workspaceId.value = context.workspaceId.value;
|
|
@@ -42,6 +45,7 @@ export function useChatRequestContext() {
|
|
|
42
45
|
if (!globalContext.provided.value)
|
|
43
46
|
return null;
|
|
44
47
|
return {
|
|
48
|
+
conversationId: computed(() => globalContext.conversationId.value),
|
|
45
49
|
harness: computed(() => globalContext.harness.value),
|
|
46
50
|
workspaceId: computed(() => globalContext.workspaceId.value),
|
|
47
51
|
telaAgentId: computed(() => globalContext.telaAgentId.value),
|
|
@@ -230,17 +230,7 @@ export declare const conversationWithMessagesSchema: z.ZodObject<{
|
|
|
230
230
|
}, z.core.$strip>;
|
|
231
231
|
export type ConversationWithMessages = z.infer<typeof conversationWithMessagesSchema>;
|
|
232
232
|
export declare const createConversationRequestSchema: z.ZodObject<{
|
|
233
|
-
model: z.ZodOptional<z.ZodNullable<z.
|
|
234
|
-
"claude-opus-5": "claude-opus-5";
|
|
235
|
-
"claude-opus-5-5": "claude-opus-5-5";
|
|
236
|
-
"claude-opus-4-8": "claude-opus-4-8";
|
|
237
|
-
"claude-sonnet-5": "claude-sonnet-5";
|
|
238
|
-
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
239
|
-
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
240
|
-
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
241
|
-
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
242
|
-
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
243
|
-
}>>>;
|
|
233
|
+
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
244
234
|
reasoningEffort: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
245
235
|
low: "low";
|
|
246
236
|
medium: "medium";
|
|
@@ -432,17 +422,7 @@ export declare const updateConversationAgentInputsResponseSchema: z.ZodObject<{
|
|
|
432
422
|
export type UpdateConversationAgentInputsResponse = z.infer<typeof updateConversationAgentInputsResponseSchema>;
|
|
433
423
|
export declare const updateConversationRequestSchema: z.ZodObject<{
|
|
434
424
|
title: z.ZodOptional<z.ZodString>;
|
|
435
|
-
model: z.ZodOptional<z.ZodNullable<z.
|
|
436
|
-
"claude-opus-5": "claude-opus-5";
|
|
437
|
-
"claude-opus-5-5": "claude-opus-5-5";
|
|
438
|
-
"claude-opus-4-8": "claude-opus-4-8";
|
|
439
|
-
"claude-sonnet-5": "claude-sonnet-5";
|
|
440
|
-
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
441
|
-
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
442
|
-
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
443
|
-
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
444
|
-
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
445
|
-
}>>>;
|
|
425
|
+
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
446
426
|
reasoningEffort: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
447
427
|
low: "low";
|
|
448
428
|
medium: "medium";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const chatModelCatalogEntrySchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
label: z.ZodString;
|
|
5
|
+
description: z.ZodNullable<z.ZodString>;
|
|
6
|
+
provider: z.ZodString;
|
|
7
|
+
cost: z.ZodNumber;
|
|
8
|
+
maxInputTokens: z.ZodNumber;
|
|
9
|
+
maxOutputTokens: z.ZodNullable<z.ZodNumber>;
|
|
10
|
+
isMultiModal: z.ZodBoolean;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
export type ChatModelCatalogEntry = z.infer<typeof chatModelCatalogEntrySchema>;
|
|
13
|
+
export declare const chatModelCatalogResponseSchema: z.ZodObject<{
|
|
14
|
+
models: z.ZodArray<z.ZodObject<{
|
|
15
|
+
id: z.ZodString;
|
|
16
|
+
label: z.ZodString;
|
|
17
|
+
description: z.ZodNullable<z.ZodString>;
|
|
18
|
+
provider: z.ZodString;
|
|
19
|
+
cost: z.ZodNumber;
|
|
20
|
+
maxInputTokens: z.ZodNumber;
|
|
21
|
+
maxOutputTokens: z.ZodNullable<z.ZodNumber>;
|
|
22
|
+
isMultiModal: z.ZodBoolean;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
catalogAvailable: z.ZodBoolean;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
export type ChatModelCatalogResponse = z.infer<typeof chatModelCatalogResponseSchema>;
|
|
27
|
+
export declare const fallbackChatModelCatalog: readonly ChatModelCatalogEntry[];
|
|
28
|
+
export declare function chatModelTabs(entry: Pick<ChatModelCatalogEntry, 'cost' | 'isMultiModal'>): string[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { chatModelOptions } from './ui';
|
|
3
|
+
export const chatModelCatalogEntrySchema = z.object({
|
|
4
|
+
id: z.string().min(1),
|
|
5
|
+
label: z.string().min(1),
|
|
6
|
+
description: z.string().nullable(),
|
|
7
|
+
provider: z.string().min(1),
|
|
8
|
+
cost: z.number().int().min(1).max(5),
|
|
9
|
+
maxInputTokens: z.number().int().positive(),
|
|
10
|
+
maxOutputTokens: z.number().int().positive().nullable(),
|
|
11
|
+
isMultiModal: z.boolean(),
|
|
12
|
+
});
|
|
13
|
+
export const chatModelCatalogResponseSchema = z.object({
|
|
14
|
+
models: z.array(chatModelCatalogEntrySchema).min(1),
|
|
15
|
+
// False when the bundled fallback is being served instead of the Agent API catalog.
|
|
16
|
+
catalogAvailable: z.boolean(),
|
|
17
|
+
});
|
|
18
|
+
export const fallbackChatModelCatalog = chatModelOptions.map(option => ({
|
|
19
|
+
id: option.value,
|
|
20
|
+
label: option.label,
|
|
21
|
+
description: option.description,
|
|
22
|
+
provider: option.provider,
|
|
23
|
+
cost: option.cost,
|
|
24
|
+
maxInputTokens: option.maxInputTokens,
|
|
25
|
+
maxOutputTokens: option.maxOutputTokens,
|
|
26
|
+
isMultiModal: option.isMultiModal,
|
|
27
|
+
}));
|
|
28
|
+
export function chatModelTabs(entry) {
|
|
29
|
+
return ['all', entry.cost <= 2 ? 'cheap' : 'advanced', ...(entry.isMultiModal ? ['multimodal'] : [])];
|
|
30
|
+
}
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const chatModelIds: readonly ["claude-opus-5", "claude-opus-5-5", "claude-opus-4-8", "claude-sonnet-5", "claude-sonnet-4-6", "claude-haiku-4-5", "openai/gpt-5.6-sol", "openai/gpt-5.6-terra", "openai/gpt-5.6-luna"];
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
"claude-opus-5-5": "claude-opus-5-5";
|
|
6
|
-
"claude-opus-4-8": "claude-opus-4-8";
|
|
7
|
-
"claude-sonnet-5": "claude-sonnet-5";
|
|
8
|
-
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
9
|
-
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
10
|
-
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
11
|
-
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
12
|
-
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
13
|
-
}>;
|
|
3
|
+
export type KnownChatModel = typeof chatModelIds[number];
|
|
4
|
+
export declare const chatModelSchema: z.ZodString;
|
|
14
5
|
export type ChatModel = z.infer<typeof chatModelSchema>;
|
|
15
6
|
export declare const defaultChatModel = "claude-opus-5";
|
|
16
|
-
export declare function isValidChatModel(value: unknown): value is
|
|
7
|
+
export declare function isValidChatModel(value: unknown): value is KnownChatModel;
|
|
17
8
|
export declare const chatReasoningEffortValues: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
18
9
|
export declare const chatReasoningEffortSchema: z.ZodEnum<{
|
|
19
10
|
low: "low";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
// Bundled catalog: the chat-api and chat-nuxt fall back to these ids when the
|
|
3
|
+
// Agent API catalog cannot be fetched. The live catalog may offer more.
|
|
2
4
|
export const chatModelIds = [
|
|
3
5
|
'claude-opus-5',
|
|
4
6
|
'claude-opus-5-5',
|
|
@@ -10,7 +12,8 @@ export const chatModelIds = [
|
|
|
10
12
|
'openai/gpt-5.6-terra',
|
|
11
13
|
'openai/gpt-5.6-luna',
|
|
12
14
|
];
|
|
13
|
-
|
|
15
|
+
// Any id the Agent API catalog exposes; the Agent API rejects unknown ones on execute.
|
|
16
|
+
export const chatModelSchema = z.string().trim().min(1);
|
|
14
17
|
export const defaultChatModel = 'claude-opus-5';
|
|
15
18
|
export function isValidChatModel(value) {
|
|
16
19
|
return typeof value === 'string' && chatModelIds.includes(value);
|
|
@@ -8,6 +8,7 @@ export * from './chat/github';
|
|
|
8
8
|
export { chatModelCatalogEntrySchema, chatModelCatalogResponseSchema, chatModelsResponseSchema, isValidChatModel as isValidLightweightChatModel, chatModelSchema as lightweightChatModelSchema, } from './chat/lightweight-models';
|
|
9
9
|
export type { ChatModelCatalogEntry, ChatModel as LightweightChatModel } from './chat/lightweight-models';
|
|
10
10
|
export * from './chat/messages';
|
|
11
|
+
export { chatModelTabs, fallbackChatModelCatalog } from './chat/model-catalog';
|
|
11
12
|
export * from './chat/models';
|
|
12
13
|
export * from './chat/primitives';
|
|
13
14
|
export * from './chat/titles';
|
|
@@ -7,6 +7,7 @@ export * from './chat/files';
|
|
|
7
7
|
export * from './chat/github';
|
|
8
8
|
export { chatModelCatalogEntrySchema, chatModelCatalogResponseSchema, chatModelsResponseSchema, isValidChatModel as isValidLightweightChatModel, chatModelSchema as lightweightChatModelSchema, } from './chat/lightweight-models';
|
|
9
9
|
export * from './chat/messages';
|
|
10
|
+
export { chatModelTabs, fallbackChatModelCatalog } from './chat/model-catalog';
|
|
10
11
|
export * from './chat/models';
|
|
11
12
|
export * from './chat/primitives';
|
|
12
13
|
export * from './chat/titles';
|
|
@@ -274,17 +274,7 @@ export declare const telaAgentSessionSchema: z.ZodObject<{
|
|
|
274
274
|
export type TelaAgentSession = z.infer<typeof telaAgentSessionSchema>;
|
|
275
275
|
export declare const telaAgentWakeRequestSchema: z.ZodObject<{
|
|
276
276
|
sessionId: z.ZodOptional<z.ZodString>;
|
|
277
|
-
model: z.ZodOptional<z.
|
|
278
|
-
"claude-opus-5": "claude-opus-5";
|
|
279
|
-
"claude-opus-5-5": "claude-opus-5-5";
|
|
280
|
-
"claude-opus-4-8": "claude-opus-4-8";
|
|
281
|
-
"claude-sonnet-5": "claude-sonnet-5";
|
|
282
|
-
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
283
|
-
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
284
|
-
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
285
|
-
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
286
|
-
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
287
|
-
}>>;
|
|
277
|
+
model: z.ZodOptional<z.ZodString>;
|
|
288
278
|
}, z.core.$strip>;
|
|
289
279
|
export type TelaAgentWakeRequest = z.infer<typeof telaAgentWakeRequestSchema>;
|
|
290
280
|
export declare const telaAgentWakeResponseSchema: z.ZodObject<{
|