WIP - ai process builder codex attempt

This commit is contained in:
Francisco Gaona
2026-01-17 20:16:04 +01:00
parent 20fc90a3fb
commit ded413b99b
34 changed files with 2199 additions and 13 deletions

View File

@@ -16,6 +16,12 @@ const messages = ref<{ role: 'user' | 'assistant'; text: string }[]>([])
const sending = ref(false)
const route = useRoute()
const { api } = useApi()
const sessionId = ref<string | null>(null)
const getTenantId = () => {
if (!import.meta.client) return 'tenant1'
return localStorage.getItem('tenantId') || 'tenant1'
}
const buildContext = () => {
const recordId = route.params.recordId ? String(route.params.recordId) : undefined
@@ -43,27 +49,39 @@ const handleSend = async () => {
try {
const history = messages.value.slice(0, -1).slice(-6)
const response = await api.post('/ai/chat', {
const response = await api.post(`/tenants/${getTenantId()}/ai-chat/messages`, {
message,
history,
context: buildContext(),
sessionId: sessionId.value || undefined,
})
if (response.sessionId) {
sessionId.value = response.sessionId
}
if (response.reply) {
messages.value.push({
role: 'assistant',
text: response.reply,
})
if (response.action === 'create_record') {
window.dispatchEvent(
new CustomEvent('ai-record-created', {
detail: {
objectApiName: buildContext().objectApiName,
record: response.record,
},
}),
)
}
return
}
messages.value.push({
role: 'assistant',
text: response.reply || 'Let me know what else you need.',
text: 'Process started. I will post updates as soon as they are ready.',
})
if (response.action === 'create_record') {
window.dispatchEvent(
new CustomEvent('ai-record-created', {
detail: {
objectApiName: buildContext().objectApiName,
record: response.record,
},
}),
)
}
} catch (error: any) {
console.error('Failed to send AI chat message:', error)
messages.value.push({

View File

@@ -0,0 +1,52 @@
<template>
<div class="rounded-lg border border-amber-200 bg-amber-50 p-4">
<p class="mb-3 text-sm font-semibold text-amber-900">{{ prompt }}</p>
<form class="space-y-3" @submit.prevent="submit">
<div v-for="field in fields" :key="field.name" class="space-y-1">
<label class="text-xs font-medium text-slate-600">
{{ field.label }}
</label>
<input
v-model="form[field.name]"
class="w-full rounded border border-slate-300 px-3 py-2 text-sm"
:type="field.type === 'number' ? 'number' : 'text'"
:required="field.required"
/>
</div>
<button
type="submit"
class="rounded bg-slate-900 px-4 py-2 text-sm font-semibold text-white"
>
Submit
</button>
</form>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{
schema: Record<string, any>
prompt: string
}>()
const emit = defineEmits<{
(event: 'submit', payload: Record<string, unknown>): void
}>()
const form = reactive<Record<string, string>>({})
const fields = computed(() => {
const properties = props.schema?.properties || {}
const required = props.schema?.required || []
return Object.entries(properties).map(([name, config]: [string, any]) => ({
name,
label: config.title || name,
type: config.type || 'string',
required: required.includes(name),
}))
})
const submit = () => {
emit('submit', { ...form })
}
</script>

View File

@@ -0,0 +1,19 @@
<template>
<div class="rounded-lg border border-slate-200 bg-white shadow">
<div class="border-b border-slate-200 px-4 py-3 text-sm font-semibold text-slate-700">
Process Graph Editor
</div>
<iframe
class="h-[640px] w-full"
:src="editorUrl"
title="AI Process Builder"
/>
</div>
</template>
<script setup lang="ts">
const config = useRuntimeConfig()
const editorUrl = computed(() =>
config.public.aiProcessEditorUrl || 'http://localhost:5174'
)
</script>