feat(ai): add the chat capability to the platform contract

A platform can now implement chat, and each AI feature shows only when
the platform implements the capability it relies on.
This commit is contained in:
nivedin
2026-09-24 15:12:54 +05:30
committed by Nivedin
parent 0d75567c96
commit 347a475512
6 changed files with 50 additions and 7 deletions
@@ -196,7 +196,7 @@ const currentRequest = computed(() =>
: null
)
const { shouldEnableAIFeatures } = useAIExperiments()
const { shouldEnableAIFeatures } = useAIExperiments("modifyPreRequestScript")
const isModifyPreRequestModalOpen = ref(false)
const currentUser = useReadonlyStream(
@@ -245,7 +245,7 @@ const showModifyBodyModal = () => {
isModifyBodyModalOpen.value = true
}
const { shouldEnableAIFeatures } = useAIExperiments()
const { shouldEnableAIFeatures } = useAIExperiments("modifyRequestBody")
const prettifyXML = (xml: string) => {
return xmlFormat(xml, {
@@ -193,7 +193,7 @@ const currentRequest = computed(() =>
: null
)
const { shouldEnableAIFeatures } = useAIExperiments()
const { shouldEnableAIFeatures } = useAIExperiments("modifyTestScript")
const isModifyTestScriptModalOpen = ref(false)
const currentUser = useReadonlyStream(
@@ -25,7 +25,10 @@ export const useRequestNameGeneration = (targetNameRef: Ref<string>) => {
const ENABLE_AI_EXPERIMENTS = useSetting("ENABLE_AI_EXPERIMENTS")
const canDoRequestNameGeneration = computed(() => {
return ENABLE_AI_EXPERIMENTS.value && !!platform.experiments?.aiExperiments
return (
ENABLE_AI_EXPERIMENTS.value &&
!!platform.experiments?.aiExperiments?.generateRequestName
)
})
const lastTraceID = ref<string | null>(null)
@@ -82,11 +85,28 @@ export const useRequestNameGeneration = (targetNameRef: Ref<string>) => {
}
}
export const useAIExperiments = () => {
/**
* The individual AI capabilities a platform may implement. Mirrors the
* function members of `ExperimentsPlatformDef["aiExperiments"]`.
*/
export type AIExperimentsCapability = keyof Omit<
NonNullable<NonNullable<typeof platform.experiments>["aiExperiments"]>,
"enableAIExperiments"
>
/**
* Whether AI features should be surfaced. Pass the capability a feature relies
* on so its UI only shows when the platform actually implements it — platforms
* may provide a subset (e.g. self-host implements only `chat`). With no
* capability given, checks only that AI experiments exist at all.
*/
export const useAIExperiments = (capability?: AIExperimentsCapability) => {
const ENABLE_AI_EXPERIMENTS = useSetting("ENABLE_AI_EXPERIMENTS")
const shouldEnableAIFeatures = computed(() => {
return ENABLE_AI_EXPERIMENTS.value && !!platform.experiments?.aiExperiments
const aiExperiments = platform.experiments?.aiExperiments
if (!ENABLE_AI_EXPERIMENTS.value || !aiExperiments) return false
return capability ? !!aiExperiments[capability] : true
})
return {
@@ -80,7 +80,7 @@
</HoppSmartToggle>
</div>
<div
v-if="hasAIExperimentsSupport && ENABLE_AI_EXPERIMENTS"
v-if="hasAIRequestNamingSupport && ENABLE_AI_EXPERIMENTS"
class="flex items-center"
>
<div class="flex flex-col space-y-2 w-full">
@@ -380,6 +380,12 @@ const confirmRemove = ref(false)
const hasAIExperimentsSupport =
!!platform.experiments?.aiExperiments?.enableAIExperiments
// The naming-style preference only matters when the platform can generate
// request names — platforms may implement just a subset of the AI features.
const hasAIRequestNamingSupport =
hasAIExperimentsSupport &&
!!platform.experiments?.aiExperiments?.generateRequestName
const showConfirmModal = () => {
if (TELEMETRY_ENABLED.value) confirmRemove.value = true
else toggleSetting("TELEMETRY_ENABLED")
@@ -43,5 +43,22 @@ export type ExperimentsPlatformDef = {
) => Promise<
E.Either<string, { modified_script: string; trace_id: string }>
>
chat?: (
messages: { role: "user" | "assistant"; content: string | unknown[] }[],
context: string
) => Promise<
E.Either<
string,
{
content: string
tool_calls: {
id: string
name: string
input: Record<string, unknown>
}[]
trace_id: string
}
>
>
}
}