Skip to content
Source
Sign inSign up

model-mentions.ts

48 lines1.9 KB

1import { useAtomValue } from "@effect/atom-react";
2import { collectComposerModelMentions } from "@t3tools/client-runtime/composer-model-mentions";
3import type { EnvironmentId } from "@t3tools/contracts";
4import * as Option from "effect/Option";
5import { Atom } from "effect/reactivity";
6​
7import { buildEnrichedModelReferences } from "../lib/enrichedLinkPresentation";
8import type { SelectableMarkdownModel } from "../native/SelectableMarkdownText.types";
9import { serverEnvironment } from "./server";
10​
11const EMPTY_MODELS: ReadonlyArray<SelectableMarkdownModel> = [];
12const emptyModelsAtom = Atom.make(EMPTY_MODELS);
13​
14const modelMentionsAtom = Atom.family((key: string) => {
15 const [environmentId, ...sources] = key.split("\n");
16 const wanted = new Set(sources);
17 return Atom.make((get) => {
18 const models = buildEnrichedModelReferences(
19 get(serverEnvironment.providersValueAtom(environmentId as EnvironmentId)) ?? [],
20 wanted,
21 );
22 const previous = Option.getOrUndefined(get.self<ReadonlyArray<SelectableMarkdownModel>>());
23 // Provider status pushes do not change a message's chip labels or artwork.
24 return previous?.length === models.length &&
25 previous.every((model, index) => {
26 const next = models[index]!;
27 return (
28 model.source === next.source &&
29 model.label === next.label &&
30 model.providerLabel === next.providerLabel &&
31 model.iconUrl === next.iconUrl
32 );
33 })
34 ? previous
35 : models;
36 }).pipe(Atom.withLabel("mobile:model-mentions"));
37});
38​
39export function useModelMentions(environmentId: EnvironmentId | undefined, markdown: string) {
40 const sources = [
41 ...new Set(collectComposerModelMentions(markdown).map((mention) => mention.source)),
42 ].sort();
43 return useAtomValue(
44 environmentId && sources.length
45 ? modelMentionsAtom([environmentId, ...sources].join("\n"))
46 : emptyModelsAtom,
47 );