From cad5919220dc2d1f7bfd8b92210bfb79d3dfd3fb Mon Sep 17 00:00:00 2001 From: Charles Yao Date: Mon, 31 Aug 2026 23:34:45 -0700 Subject: [PATCH] refactor(dify-builder): generate contract TS into @dify/contracts/dify-builder Co-Authored-By: Claude Opus 4.8 --- api/core/dify_builder/contract_gen.py | 2 +- .../core/dify_builder/test_contract.py | 2 +- .../contracts/generated/dify-builder/types.ts | 69 +++++++++++++++++++ packages/contracts/package.json | 5 ++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 packages/contracts/generated/dify-builder/types.ts diff --git a/api/core/dify_builder/contract_gen.py b/api/core/dify_builder/contract_gen.py index 3f7c2dbbf27..c47bf63ff86 100644 --- a/api/core/dify_builder/contract_gen.py +++ b/api/core/dify_builder/contract_gen.py @@ -243,7 +243,7 @@ def main() -> None: repo_root = next(p for p in Path(__file__).parents if (p / "web").is_dir() and (p / "api").is_dir()) schema_path = Path(__file__).with_name("contract_schema.json") - ts_path = repo_root / "web" / "app" / "components" / "dify-builder" / "contract" / "types.ts" + ts_path = repo_root / "packages" / "contracts" / "generated" / "dify-builder" / "types.ts" schema_path.write_text(json.dumps(schema, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") ts_path.parent.mkdir(parents=True, exist_ok=True) diff --git a/api/tests/unit_tests/core/dify_builder/test_contract.py b/api/tests/unit_tests/core/dify_builder/test_contract.py index 6a99dd95ea9..e9a8e055398 100644 --- a/api/tests/unit_tests/core/dify_builder/test_contract.py +++ b/api/tests/unit_tests/core/dify_builder/test_contract.py @@ -255,7 +255,7 @@ def test_schema_in_lockstep(): schema, ts = contract_gen.generate() root = next(p for p in Path(__file__).parents if (p / "web").is_dir() and (p / "api").is_dir()) checked_json = (root / "api/core/dify_builder/contract_schema.json").read_text() - checked_ts = (root / "web/app/components/dify-builder/contract/types.ts").read_text() + checked_ts = (root / "packages/contracts/generated/dify-builder/types.ts").read_text() regen_hint = "run: uv run --directory api python -m core.dify_builder.contract_gen" assert json.dumps(schema, indent=2, ensure_ascii=False) + "\n" == checked_json, regen_hint assert ts == checked_ts, regen_hint diff --git a/packages/contracts/generated/dify-builder/types.ts b/packages/contracts/generated/dify-builder/types.ts new file mode 100644 index 00000000000..3ccf2346fda --- /dev/null +++ b/packages/contracts/generated/dify-builder/types.ts @@ -0,0 +1,69 @@ +// AUTO-GENERATED by api/core/dify_builder/contract_gen.py — do not edit by hand. +// Regenerate: uv run --directory api python -m core.dify_builder.contract_gen +export type Phase = 'understand' | 'clarify' | 'resources' | 'plan' | 'modify' | 'test' | 'review' | 'publish' | 'complete'; +export type RunStatus = 'thinking' | 'executing' | 'waiting_input' | 'waiting_confirmation' | 'paused' | 'failed' | 'complete'; +export type ActionKind = 'primary' | 'secondary' | 'destructive' | 'automatic'; +export type CardKind = 'user' | 'decision' | 'notice' | 'run_context' | 'preflight_context' | 'assistant_turn' | 'plan' | 'form' | 'challenge' | 'resource_select' | 'checkpoint' | 'change_set' | 'test_result' | 'error' | 'summary' | 'publish' | 'build_learning'; +export type CanvasEvent = 'reset_build_canvas' | 'add_start_node' | 'add_knowledge_node' | 'add_llm_node' | 'add_output_node' | 'focus_workflow' | 'highlight_edit_target' | 'apply_edit_plan' | 'start_test_run' | 'mark_test_error' | 'focus_error_node' | 'focus_checklist_node' | 'create_checkpoint' | 'apply_error_fix' | 'mark_repair_applied' | 'apply_preflight_fix' | 'start_retest' | 'mark_test_success' | 'mark_review_ready' | 'revert_checkpoint' | 'cancel_publish' | 'publish_workflow'; +export type ConflictPolicy = 'audited' | 'ask'; +export type SkillLearningPolicy = 'ask' | 'automatic' | 'disabled'; +export type RecoveryClass = 'unchanged' | 'config_only' | 'structural_compatible' | 'structural_invalidating'; +export type EntryMode = 'fix' | 'fix_checklist' | 'build' | 'edit'; +export interface Action { id: string; label: string; kind: ActionKind; next_state?: string | null; canvas_event?: string | null; } +export interface CheckpointRef { checkpoint_id: string; label: string; created_at: string; } +export interface RecoveryRef { recovery_class: string; can_continue: boolean; can_restart: boolean; message: string; } +export interface FormField { key: string; label: string; type: string; options?: string[]; } +export interface ResourceOption { id: string; label: string; meta: string; kind: string; readiness: string; } +export interface SessionModel { provider: string; name: string; mode?: string; completion_params?: Record; } +export interface ConflictPolicyOption { id: string; label: string; recommended?: boolean; } +export interface PreflightIssue { node_id: string; label: string; kind: string; } +export interface TraceStep { id: string; label: string; state: string; tone?: string; canvas_event?: string | null; } +export interface Trace { status: string; steps?: TraceStep[]; } +export interface TestStat { value: string; label: string; } +export interface SummaryRow { label: string; value: string; } +export interface UserItem { text: string; } +export interface DecisionItem { text: string; } +export interface NoticeItem { text: string; tone?: string; } +export interface RunContextCard { run_id: string; title: string; error_code: string; message: string; trace_ref?: string; } +export interface PreflightContextCard { node_count: number; issue_count: number; issues?: PreflightIssue[]; } +export interface AssistantTurnItem { turn_id: string; stage_id: string; trace: Trace; reply_text?: string | null; cards?: string[]; card_state?: string | null; } +export interface PlanCard { title: string; version_tag: string; items?: string[]; subtitle?: string | null; } +export interface FormCard { variant: string; fields?: FormField[]; values?: Record; frozen?: boolean; } +export interface ChallengeCard { title: string; body: string; tone?: string; } +export interface ResourceSelectCard { recommended?: ResourceOption[]; conflict_policy_options?: ConflictPolicyOption[]; } +export interface CheckpointCard { checkpoint_id: string; label: string; created_at: string; } +export interface ChangeSetCard { count: number; changes: string[]; scope: string; full_diff_open?: boolean; } +export interface TestResultCard { title: string; subtitle: string; tone: string; stats?: TestStat[]; run_ids?: string[]; } +export interface ErrorCard { title: string; body: string; tone?: string; node_id?: string | null; } +export interface SummaryCard { variant: string; title?: string | null; items?: string[]; rows?: SummaryRow[]; } +export interface PublishCard { version: string; badge?: string; } +export interface BuildLearningCard { policy: string; state: string; } +export interface GoalPayload { text: string; } +export interface EditGoalPayload { text: string; } +export interface RequirementsPayload { report_types: string; audience: string; currency: string; metrics: string; output: string; prefer_audited?: boolean; } +export interface EditRulesPayload { risk_threshold: string; review_team: string; timeout_behavior: string; preserve_summary?: boolean; } +export interface ResourcesPayload { conflict_policy: string; resource_ids?: string[]; } +export interface RunContextPayload { run_id: string; node_name: string; error_code: string; } +export interface CheckpointPayload { checkpoint_id: string; } +export interface TestPayload { run_ids?: string[]; } +export interface PublishPayload { version: string; } +export interface TestdataPayload { mode: string; inputs?: Record | null; } +export interface SessionView { session_id: string; app_id: string; version: number; state: string; canvas_read_only: boolean; run_status: RunStatus; interrupted: boolean; conversation: ConversationItem[]; entry_mode?: EntryMode; phase?: Phase; actions?: Action[]; checkpoint?: CheckpointRef | null; recovery?: RecoveryRef | null; model?: SessionModel | null; } +export type ConversationItem = + | { seq: number; at_version: number; kind: 'user'; payload: UserItem } + | { seq: number; at_version: number; kind: 'decision'; payload: DecisionItem } + | { seq: number; at_version: number; kind: 'notice'; payload: NoticeItem } + | { seq: number; at_version: number; kind: 'run_context'; payload: RunContextCard } + | { seq: number; at_version: number; kind: 'preflight_context'; payload: PreflightContextCard } + | { seq: number; at_version: number; kind: 'assistant_turn'; payload: AssistantTurnItem } + | { seq: number; at_version: number; kind: 'plan'; payload: PlanCard } + | { seq: number; at_version: number; kind: 'form'; payload: FormCard } + | { seq: number; at_version: number; kind: 'challenge'; payload: ChallengeCard } + | { seq: number; at_version: number; kind: 'resource_select'; payload: ResourceSelectCard } + | { seq: number; at_version: number; kind: 'checkpoint'; payload: CheckpointCard } + | { seq: number; at_version: number; kind: 'change_set'; payload: ChangeSetCard } + | { seq: number; at_version: number; kind: 'test_result'; payload: TestResultCard } + | { seq: number; at_version: number; kind: 'error'; payload: ErrorCard } + | { seq: number; at_version: number; kind: 'summary'; payload: SummaryCard } + | { seq: number; at_version: number; kind: 'publish'; payload: PublishCard } + | { seq: number; at_version: number; kind: 'build_learning'; payload: BuildLearningCard }; diff --git a/packages/contracts/package.json b/packages/contracts/package.json index c8e5916c6a6..48adfd92fe3 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -27,6 +27,10 @@ "./knowledge-fs/*": { "types": "./generated/knowledge-fs/*.ts", "import": "./generated/knowledge-fs/*.ts" + }, + "./dify-builder": { + "types": "./generated/dify-builder/types.ts", + "import": "./generated/dify-builder/types.ts" } }, "scripts": { @@ -34,6 +38,7 @@ "gen-enterprise-contract": "openapi-ts -f openapi-ts.enterprise.config.ts", "gen-enterprise-app-deploy-contract": "openapi-ts -f openapi-ts.enterprise-app-deploy.config.ts", "gen-knowledge-fs-contract": "node scripts/generate-knowledge-fs-contract.mjs", + "gen-dify-builder-contract": "uv run --project ../../api python -m core.dify_builder.contract_gen", "test": "vp test", "type-check": "tsc" },