Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
189 lines
4.5 KiB
TypeScript
189 lines
4.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import {
|
|
buildWorkflowAiSimpleSchema,
|
|
hydrateWorkflowAiSimpleFields,
|
|
parseWorkflowAiSchemaText,
|
|
resolveWorkflowAiSchemaFromConfig,
|
|
validateWorkflowAiSchema,
|
|
type WorkflowAiSimpleField,
|
|
type WorkflowJsonSchema,
|
|
} from '../aiSchema';
|
|
|
|
const simpleFields: WorkflowAiSimpleField[] = [
|
|
{
|
|
id: 'summary',
|
|
name: 'summary',
|
|
type: 'string',
|
|
required: true,
|
|
description: 'Short summary',
|
|
},
|
|
{
|
|
id: 'sentiment',
|
|
name: 'sentiment',
|
|
type: 'string',
|
|
required: false,
|
|
description: 'Overall tone',
|
|
},
|
|
{
|
|
id: 'details',
|
|
name: 'details',
|
|
type: 'object',
|
|
required: false,
|
|
children: [
|
|
{
|
|
id: 'confidence',
|
|
name: 'confidence',
|
|
type: 'number',
|
|
required: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'tags',
|
|
name: 'tags',
|
|
type: 'array',
|
|
required: false,
|
|
arrayItemType: 'string',
|
|
},
|
|
{
|
|
id: 'actions',
|
|
name: 'actions',
|
|
type: 'array',
|
|
required: false,
|
|
arrayItemType: 'object',
|
|
children: [
|
|
{
|
|
id: 'label',
|
|
name: 'label',
|
|
type: 'string',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'priority',
|
|
name: 'priority',
|
|
type: 'integer',
|
|
required: false,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
describe('workflow ai schema utilities', () => {
|
|
it('T011/T012/T013/T014/T015/T016/T017: simple builder serializes the supported object-root subset canonically', () => {
|
|
expect(buildWorkflowAiSimpleSchema(simpleFields)).toEqual({
|
|
type: 'object',
|
|
properties: {
|
|
summary: {
|
|
type: 'string',
|
|
description: 'Short summary',
|
|
},
|
|
sentiment: {
|
|
type: 'string',
|
|
description: 'Overall tone',
|
|
},
|
|
details: {
|
|
type: 'object',
|
|
properties: {
|
|
confidence: {
|
|
type: 'number',
|
|
},
|
|
},
|
|
additionalProperties: false,
|
|
required: ['confidence'],
|
|
},
|
|
tags: {
|
|
type: 'array',
|
|
items: {
|
|
type: 'string',
|
|
},
|
|
},
|
|
actions: {
|
|
type: 'array',
|
|
items: {
|
|
type: 'object',
|
|
properties: {
|
|
label: {
|
|
type: 'string',
|
|
},
|
|
priority: {
|
|
type: 'integer',
|
|
},
|
|
},
|
|
additionalProperties: false,
|
|
required: ['label'],
|
|
},
|
|
},
|
|
},
|
|
additionalProperties: false,
|
|
required: ['summary'],
|
|
});
|
|
});
|
|
|
|
it('T019: advanced schema validation rejects invalid JSON and unsupported v1 constructs', () => {
|
|
expect(parseWorkflowAiSchemaText('{')).toMatchObject({
|
|
schema: null,
|
|
});
|
|
|
|
expect(
|
|
validateWorkflowAiSchema(
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
result: {
|
|
anyOf: [{ type: 'string' }, { type: 'number' }],
|
|
},
|
|
},
|
|
},
|
|
'advanced'
|
|
)
|
|
).toContain('AI output schema.properties.result cannot use anyOf in v1.');
|
|
});
|
|
|
|
it('T020: simple-compatible saved schemas rehydrate into the simple field tree', () => {
|
|
const schema = buildWorkflowAiSimpleSchema(simpleFields);
|
|
const hydrated = hydrateWorkflowAiSimpleFields(schema);
|
|
|
|
expect(hydrated.ok).toBe(true);
|
|
if (!hydrated.ok) return;
|
|
expect(hydrated.fields).toHaveLength(5);
|
|
expect(hydrated.fields.find((field) => field.name === 'details')?.children?.[0]).toMatchObject({
|
|
name: 'confidence',
|
|
type: 'number',
|
|
required: true,
|
|
});
|
|
expect(hydrated.fields.find((field) => field.name === 'actions')).toMatchObject({
|
|
type: 'array',
|
|
arrayItemType: 'object',
|
|
});
|
|
});
|
|
|
|
it('T021: advanced-only schemas stay out of simple mode without lossy conversion', () => {
|
|
const advancedOnlySchema: WorkflowJsonSchema = {
|
|
type: 'object',
|
|
properties: {
|
|
result: {
|
|
type: 'object',
|
|
additionalProperties: {
|
|
type: 'string',
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
const hydrated = hydrateWorkflowAiSimpleFields(advancedOnlySchema);
|
|
expect(hydrated).toEqual({
|
|
ok: false,
|
|
reason: 'Simple mode does not support map-style object fields on result.',
|
|
});
|
|
|
|
const resolved = resolveWorkflowAiSchemaFromConfig({
|
|
actionId: 'ai.infer',
|
|
aiOutputSchemaMode: 'advanced',
|
|
aiOutputSchemaText: JSON.stringify(advancedOnlySchema),
|
|
});
|
|
expect(resolved.schema).toEqual(advancedOnlySchema);
|
|
expect(resolved.errors).toEqual([]);
|
|
});
|
|
});
|