From 180d49947f1401271933a2948f1eb20716c4a187 Mon Sep 17 00:00:00 2001 From: John Smith Date: Thu, 28 Nov 2024 14:54:02 +1030 Subject: [PATCH] feat: Open source Inferable app and control plane (#142) --- .github/workflows/build.yml | 115 + app/.dockerignore | 36 + app/.eslintrc.json | 14 + app/Dockerfile.dev | 16 + app/README.md | 36 + app/app/cli-auth/page.tsx | 67 + .../configs/[promptId]/edit/page.tsx | 261 + .../[clusterId]/configs/global/page.tsx | 195 + .../clusters/[clusterId]/configs/layout.tsx | 3 + .../clusters/[clusterId]/configs/new/page.tsx | 105 + app/app/clusters/[clusterId]/configs/page.tsx | 220 + .../integrations/langfuse/page.tsx | 232 + .../[clusterId]/integrations/layout.tsx | 3 + .../[clusterId]/integrations/page.tsx | 145 + .../integrations/toolhouse/page.tsx | 165 + .../knowledge/[artifactId]/edit/page.tsx | 80 + .../clusters/[clusterId]/knowledge/layout.tsx | 270 + .../[clusterId]/knowledge/new/page.tsx | 54 + .../clusters/[clusterId]/knowledge/page.tsx | 13 + app/app/clusters/[clusterId]/layout.tsx | 16 + app/app/clusters/[clusterId]/page.tsx | 516 + .../[clusterId]/runs/[runId]/page.tsx | 28 + app/app/clusters/[clusterId]/runs/layout.tsx | 50 + app/app/clusters/[clusterId]/runs/page.tsx | 67 + .../[clusterId]/settings/api-keys/page.tsx | 9 + .../[clusterId]/settings/danger/page.tsx | 123 + .../[clusterId]/settings/details/page.tsx | 235 + .../clusters/[clusterId]/settings/layout.tsx | 43 + .../clusters/[clusterId]/settings/page.tsx | 13 + app/app/clusters/[clusterId]/usage/page.tsx | 510 + app/app/clusters/layout.tsx | 16 + app/app/clusters/page.tsx | 70 + app/app/favicon.ico | Bin 0 -> 107164 bytes app/app/favicon.ico- | Bin 0 -> 112920 bytes app/app/globals.css | 137 + app/app/layout.tsx | 80 + app/app/page.tsx | 5 + app/app/providers.tsx | 16 + app/app/switch-org/page.tsx | 13 + app/client/client.ts | 17 + app/client/contract.ts | 1525 ++ app/components.json | 17 + app/components/FakeProgress.tsx | 27 + app/components/KnowledgeArtifactForm.tsx | 149 + app/components/OrgList.tsx | 23 + app/components/PromptMetricsCharts.tsx | 446 + app/components/ThinkingIndicator.tsx | 44 + app/components/WorkflowList.tsx | 234 + app/components/api-keys.tsx | 141 + app/components/breadcrumbs.tsx | 97 + app/components/bug-report-dialog.tsx | 255 + app/components/chat/ResultTable.css | 11 + app/components/chat/Summarizable.tsx | 19 + app/components/chat/ToolContextButton.tsx | 227 + app/components/chat/ai-message.tsx | 127 + app/components/chat/blob.tsx | 64 + app/components/chat/event-indicator.tsx | 37 + app/components/chat/function-call.tsx | 229 + app/components/chat/human-message.tsx | 166 + app/components/chat/input-fields.tsx | 71 + app/components/chat/prompt-template-form.tsx | 291 + app/components/chat/prompt-textarea.tsx | 265 + app/components/chat/run-config.tsx | 132 + app/components/chat/sdk-commands.tsx | 175 + .../chat/structured-output-editor.tsx | 293 + app/components/chat/template-mesage.tsx | 139 + app/components/chat/template-search.tsx | 111 + app/components/chat/tool-input.tsx | 149 + app/components/chat/typable.tsx | 23 + app/components/chat/workflow-event.tsx | 68 + app/components/circles.tsx | 59 + app/components/cluster-card.tsx | 132 + app/components/cluster-details.tsx | 127 + app/components/cluster-health-plane.tsx | 133 + app/components/cluster-list.tsx | 40 + app/components/copy-button.tsx | 26 + app/components/create-api-key.tsx | 111 + app/components/create-cluster-button.tsx | 49 + app/components/crisp-chat.tsx | 14 + app/components/debug-event.tsx | 114 + app/components/error-display.tsx | 90 + app/components/events-overlay.tsx | 541 + .../fetch-rerender-error.example.md | 49 + app/components/header.tsx | 38 + app/components/instructions-editor.css | 111 + app/components/instructions-editor.tsx | 347 + app/components/job-references.tsx | 149 + app/components/json-form.tsx | 551 + app/components/knowledge-quickstart.tsx | 65 + app/components/loading.tsx | 39 + app/components/logo-2.png | Bin 0 -> 67849 bytes app/components/logo.png | Bin 0 -> 107164 bytes app/components/markdown-editor.tsx | 52 + app/components/mdxeditor.css | 93 + app/components/posthog-pageview.tsx | 25 + app/components/posthog-user.tsx | 46 + app/components/read-only-json.tsx | 31 + app/components/rollbar-user.tsx | 23 + app/components/server-connection-pane.tsx | 163 + app/components/service-details-pane.tsx | 18 + app/components/services-overview.tsx | 121 + app/components/services-quickstart.tsx | 135 + app/components/ui/accordion.tsx | 58 + app/components/ui/alert-dialog.tsx | 141 + app/components/ui/alert.tsx | 59 + app/components/ui/badge.tsx | 36 + app/components/ui/breadcrumb.tsx | 115 + app/components/ui/button.tsx | 56 + app/components/ui/card.tsx | 86 + app/components/ui/chart.tsx | 365 + app/components/ui/checkbox.tsx | 30 + app/components/ui/collapsible.tsx | 11 + app/components/ui/command.tsx | 155 + app/components/ui/data-table.tsx | 119 + app/components/ui/dialog.tsx | 122 + app/components/ui/drawer.tsx | 118 + app/components/ui/dropdown-menu.tsx | 200 + app/components/ui/form.tsx | 179 + app/components/ui/input.tsx | 25 + app/components/ui/label.tsx | 26 + app/components/ui/menubar.tsx | 236 + app/components/ui/multiselect.tsx | 0 app/components/ui/popover.tsx | 31 + app/components/ui/progress.tsx | 28 + app/components/ui/scroll-area.tsx | 48 + app/components/ui/select.tsx | 160 + app/components/ui/sheet.tsx | 140 + app/components/ui/skeleton.tsx | 15 + app/components/ui/switch.tsx | 29 + app/components/ui/table.tsx | 117 + app/components/ui/tabs.tsx | 55 + app/components/ui/textarea.tsx | 24 + app/components/ui/toggle-group.tsx | 61 + app/components/ui/toggle.tsx | 45 + app/components/ui/tooltip.tsx | 30 + app/components/workflow-tab.tsx | 278 + app/components/workflow.tsx | 555 + app/lib/auth.ts | 9 + app/lib/colorize-json.ts | 24 + app/lib/encryption.ts | 74 + app/lib/types.ts | 27 + app/lib/use-authenticated-client.ts | 18 + app/lib/utils.ts | 50 + app/middleware.ts | 10 + app/next.config.mjs | 16 + app/package-lock.json | 13269 ++++++++++ app/package.json | 102 + app/pages/api/health.ts | 5 + app/postcss.config.mjs | 8 + app/styles/button-animations.css | 103 + app/tailwind.config.ts | 80 + app/tsconfig.json | 26 + control-plane/.dockerignore | 1 + control-plane/.eslintrc | 20 + control-plane/@types/fastify/index.d.ts | 8 + control-plane/Dockerfile.dev | 12 + control-plane/README.md | 35 + control-plane/babel.config.js | 6 + control-plane/docker-compose.dev.yml | 46 + control-plane/drizzle.config.ts | 14 + control-plane/drizzle/0000_odd_tattoo.sql | 60 + .../drizzle/0001_tense_dreaming_celestial.sql | 7 + control-plane/drizzle/0002_steady_korath.sql | 6 + .../drizzle/0003_living_captain_america.sql | 2 + .../drizzle/0004_confused_goliath.sql | 1 + .../drizzle/0005_overconfident_hex.sql | 5 + .../drizzle/0006_ambiguous_wild_pack.sql | 1 + control-plane/drizzle/0007_icy_the_hand.sql | 8 + .../drizzle/0008_omniscient_mongu.sql | 1 + control-plane/drizzle/0009_cuddly_medusa.sql | 4 + .../drizzle/0010_curious_amphibian.sql | 1 + control-plane/drizzle/0011_thin_preak.sql | 2 + control-plane/drizzle/0012_manual_make.sql | 2 + .../drizzle/0013_bitter_lily_hollister.sql | 1 + control-plane/drizzle/0014_kind_mercury.sql | 4 + control-plane/drizzle/0015_flimsy_microbe.sql | 2 + .../drizzle/0016_unique_wallflower.sql | 1 + .../drizzle/0017_purple_captain_stacy.sql | 14 + .../drizzle/0018_spooky_sasquatch.sql | 1 + .../drizzle/0019_early_silver_sable.sql | 4 + control-plane/drizzle/0020_third_lockjaw.sql | 2 + control-plane/drizzle/0021_brave_eternals.sql | 18 + .../0022_bizarre_princess_powerful.sql | 4 + .../drizzle/0023_lazy_dakota_north.sql | 2 + .../drizzle/0024_thin_black_bolt.sql | 4 + .../drizzle/0025_hot_shinobi_shaw.sql | 1 + .../drizzle/0026_freezing_clint_barton.sql | 30 + .../drizzle/0027_lyrical_ken_ellis.sql | 2 + .../drizzle/0028_parallel_karen_page.sql | 1 + .../drizzle/0029_sad_thunderbird.sql | 1 + .../0030_omniscient_jamie_braddock.sql | 1 + .../drizzle/0031_misty_slipstream.sql | 15 + .../drizzle/0032_clumsy_gressill.sql | 6 + control-plane/drizzle/0033_high_komodo.sql | 1 + .../drizzle/0034_real_big_bertha.sql | 2 + .../drizzle/0035_eminent_fantastic_four.sql | 2 + .../drizzle/0036_ambiguous_human_robot.sql | 13 + .../drizzle/0037_empty_molecule_man.sql | 6 + .../drizzle/0038_woozy_tiger_shark.sql | 1 + .../drizzle/0039_puzzling_vampiro.sql | 3 + control-plane/drizzle/0040_mean_jazinda.sql | 3 + .../drizzle/0041_youthful_steve_rogers.sql | 25 + control-plane/drizzle/0042_kind_lester.sql | 17 + .../drizzle/0043_closed_weapon_omega.sql | 20 + control-plane/drizzle/0044_fancy_landau.sql | 3 + control-plane/drizzle/0045_icy_kid_colt.sql | 4 + control-plane/drizzle/0046_needy_brood.sql | 7 + .../drizzle/0047_certain_penance.sql | 1 + .../drizzle/0048_awesome_joystick.sql | 3 + control-plane/drizzle/0049_gray_ben_grimm.sql | 4 + control-plane/drizzle/0050_slimy_hulk.sql | 14 + .../drizzle/0051_loving_phil_sheldon.sql | 1 + control-plane/drizzle/0052_swift_microbe.sql | 1 + control-plane/drizzle/0053_broken_zaran.sql | 3 + .../drizzle/0054_graceful_mentallo.sql | 1 + .../drizzle/0055_condemned_doomsday.sql | 11 + control-plane/drizzle/0056_chief_havok.sql | 1 + .../drizzle/0057_ambiguous_firebird.sql | 14 + .../drizzle/0058_bumpy_radioactive_man.sql | 16 + control-plane/drizzle/0059_misty_shaman.sql | 2 + .../drizzle/0060_normal_midnight.sql | 3 + .../drizzle/0061_nervous_triathlon.sql | 1 + control-plane/drizzle/0062_wide_warpath.sql | 1 + control-plane/drizzle/0063_high_lockjaw.sql | 11 + .../drizzle/0064_sweet_silverclaw.sql | 1 + control-plane/drizzle/0065_fast_oracle.sql | 16 + control-plane/drizzle/0066_fearless_storm.sql | 6 + .../drizzle/0067_outstanding_deadpool.sql | 1 + .../drizzle/0068_tranquil_deadpool.sql | 2 + .../drizzle/0069_sudden_longshot.sql | 7 + control-plane/drizzle/0070_real_wraith.sql | 3 + control-plane/drizzle/0071_tidy_jimmy_woo.sql | 2 + .../drizzle/0072_right_slipstream.sql | 13 + .../drizzle/0073_nervous_chamber.sql | 1 + .../drizzle/0074_ancient_roxanne_simpson.sql | 11 + .../0075_outgoing_christian_walker.sql | 5 + .../drizzle/0076_demonic_captain_flint.sql | 1 + control-plane/drizzle/0077_bitter_ulik.sql | 1 + .../drizzle/0078_wonderful_penance.sql | 1 + .../drizzle/0079_reflective_mathemanic.sql | 1 + .../drizzle/0080_simple_jimmy_woo.sql | 40 + .../drizzle/0081_spicy_spencer_smythe.sql | 15 + control-plane/drizzle/0082_slimy_kronos.sql | 10 + control-plane/drizzle/0083_natural_rhino.sql | 1 + control-plane/drizzle/0084_red_terrax.sql | 16 + .../drizzle/0085_conscious_purifiers.sql | 3 + .../drizzle/0086_ambiguous_swarm.sql | 1 + .../drizzle/0087_simple_stone_men.sql | 5 + .../drizzle/0088_simple_longshot.sql | 1 + control-plane/drizzle/0089_amazing_vargas.sql | 2 + .../drizzle/0090_ambitious_chimera.sql | 23 + .../drizzle/0091_living_the_professor.sql | 3 + .../drizzle/0092_overrated_sunfire.sql | 2 + control-plane/drizzle/0093_bumpy_skreet.sql | 6 + .../drizzle/0094_complex_clint_barton.sql | 1 + .../drizzle/0095_daffy_king_cobra.sql | 4 + .../drizzle/0096_romantic_namorita.sql | 3 + control-plane/drizzle/0097_cool_pyro.sql | 1 + .../drizzle/0098_gorgeous_hellion.sql | 15 + control-plane/drizzle/0099_clever_gamora.sql | 2 + control-plane/drizzle/0100_fuzzy_redwing.sql | 1 + control-plane/drizzle/0101_magical_zarek.sql | 1 + control-plane/drizzle/0102_massive_exiles.sql | 2 + .../drizzle/0103_nervous_kid_colt.sql | 1 + control-plane/drizzle/0104_salty_ultron.sql | 1 + control-plane/drizzle/0105_bouncy_wallow.sql | 1 + .../drizzle/0106_happy_moondragon.sql | 6 + .../drizzle/0107_hesitant_thaddeus_ross.sql | 6 + control-plane/drizzle/0108_little_rhino.sql | 1 + .../drizzle/0109_majestic_otto_octavius.sql | 1 + .../drizzle/0110_round_captain_britain.sql | 1 + .../drizzle/0111_sturdy_black_widow.sql | 13 + .../drizzle/0112_funny_red_ghost.sql | 1 + .../drizzle/0113_overjoyed_scream.sql | 1 + control-plane/drizzle/0114_bright_mesmero.sql | 2 + control-plane/drizzle/0115_lonely_talon.sql | 29 + control-plane/drizzle/0116_far_justice.sql | 1 + .../drizzle/0117_perfect_frightful_four.sql | 3 + control-plane/drizzle/0118_red_garia.sql | 1 + control-plane/drizzle/0119_sour_tinkerer.sql | 5 + .../drizzle/0120_fearless_krista_starr.sql | 7 + .../drizzle/0121_silky_wolverine.sql | 3 + .../drizzle/0122_nice_black_tarantula.sql | 6 + .../drizzle/0123_woozy_squirrel_girl.sql | 1 + .../drizzle/0124_careless_harpoon.sql | 1 + .../drizzle/0125_remarkable_cable.sql | 1 + .../drizzle/0126_tiresome_glorian.sql | 1 + .../drizzle/0127_illegal_james_howlett.sql | 7 + .../drizzle/0128_tricky_steel_serpent.sql | 1 + .../drizzle/0129_military_crystal.sql | 2 + .../drizzle/0130_brief_ben_parker.sql | 1 + .../drizzle/0131_regular_demogoblin.sql | 1 + .../drizzle/0132_elite_lady_bullseye.sql | 1 + control-plane/drizzle/0133_nice_luckman.sql | 1 + .../drizzle/0134_tiny_anita_blake.sql | 2 + .../drizzle/0135_majestic_callisto.sql | 18 + control-plane/drizzle/0136_many_nightmare.sql | 3 + .../drizzle/0137_remarkable_hardball.sql | 5 + .../drizzle/0138_lively_the_leader.sql | 21 + control-plane/drizzle/0139_lean_forge.sql | 1 + .../drizzle/0140_windy_grim_reaper.sql | 19 + control-plane/drizzle/0141_real_hex.sql | 1 + control-plane/drizzle/0142_opposite_leo.sql | 1 + .../0143_overconfident_lady_mastermind.sql | 15 + control-plane/drizzle/0144_crazy_shriek.sql | 2 + .../drizzle/0145_smart_weapon_omega.sql | 27 + .../drizzle/0146_moaning_rattler.sql | 32 + control-plane/drizzle/0147_clammy_ulik.sql | 3 + .../drizzle/0148_slimy_alex_wilder.sql | 2 + control-plane/drizzle/0149_last_nighthawk.sql | 1 + control-plane/drizzle/0150_giant_bishop.sql | 2 + .../drizzle/0151_careless_romulus.sql | 1 + .../drizzle/0152_strong_tomorrow_man.sql | 3 + .../drizzle/0153_unique_starhawk.sql | 4 + .../drizzle/0154_tiresome_orphan.sql | 1 + .../drizzle/0155_lush_shadow_king.sql | 9 + control-plane/drizzle/0156_old_justice.sql | 1 + control-plane/drizzle/0157_icy_hawkeye.sql | 20 + .../drizzle/0158_lush_machine_man.sql | 1 + .../drizzle/0159_lazy_quentin_quire.sql | 1 + .../drizzle/0159_tranquil_tempest.sql | 1 + .../drizzle/0160_breezy_roulette.sql | 2 + .../drizzle/0161_jazzy_lucky_pierre.sql | 1 + control-plane/drizzle/0162_sour_romulus.sql | 1 + control-plane/drizzle/0163_dizzy_ogun.sql | 1 + control-plane/drizzle/0164_large_zzzax.sql | 1 + control-plane/drizzle/0165_nice_angel.sql | 1 + control-plane/drizzle/0166_same_gargoyle.sql | 2 + .../drizzle/0167_high_silver_fox.sql | 2 + control-plane/drizzle/0168_wet_prima.sql | 5 + .../drizzle/0169_modern_big_bertha.sql | 5 + .../drizzle/0170_wet_steve_rogers.sql | 3 + control-plane/drizzle/0171_wise_bloodaxe.sql | 3 + .../drizzle/0172_sweet_jane_foster.sql | 1 + .../drizzle/0173_outstanding_silvermane.sql | 1 + .../drizzle/0174_careful_silhouette.sql | 1 + control-plane/drizzle/0175_clever_cardiac.sql | 1 + .../drizzle/0176_loose_wilson_fisk.sql | 1 + .../drizzle/0177_bright_machine_man.sql | 2 + .../drizzle/0178_thankful_hellcat.sql | 1 + control-plane/drizzle/0179_tranquil_mongu.sql | 3 + .../drizzle/0180_clumsy_sheva_callister.sql | 1 + .../drizzle/0181_oval_shadow_king.sql | 1 + .../drizzle/0182_lethal_darkstar.sql | 2 + .../drizzle/0183_black_multiple_man.sql | 14 + .../drizzle/0184_nervous_jubilee.sql | 6 + .../drizzle/0185_many_thunderbolt.sql | 1 + control-plane/drizzle/0186_oval_maggott.sql | 2 + .../drizzle/0187_sour_black_queen.sql | 2 + control-plane/drizzle/meta/0000_snapshot.json | 255 + control-plane/drizzle/meta/0001_snapshot.json | 121 + control-plane/drizzle/meta/0002_snapshot.json | 121 + control-plane/drizzle/meta/0003_snapshot.json | 134 + control-plane/drizzle/meta/0004_snapshot.json | 140 + control-plane/drizzle/meta/0005_snapshot.json | 142 + control-plane/drizzle/meta/0006_snapshot.json | 146 + control-plane/drizzle/meta/0007_snapshot.json | 193 + control-plane/drizzle/meta/0008_snapshot.json | 187 + control-plane/drizzle/meta/0009_snapshot.json | 171 + control-plane/drizzle/meta/0010_snapshot.json | 171 + control-plane/drizzle/meta/0011_snapshot.json | 181 + control-plane/drizzle/meta/0012_snapshot.json | 181 + control-plane/drizzle/meta/0013_snapshot.json | 181 + control-plane/drizzle/meta/0014_snapshot.json | 181 + control-plane/drizzle/meta/0015_snapshot.json | 195 + control-plane/drizzle/meta/0016_snapshot.json | 201 + control-plane/drizzle/meta/0017_snapshot.json | 256 + control-plane/drizzle/meta/0018_snapshot.json | 242 + control-plane/drizzle/meta/0019_snapshot.json | 231 + control-plane/drizzle/meta/0020_snapshot.json | 240 + control-plane/drizzle/meta/0021_snapshot.json | 301 + control-plane/drizzle/meta/0022_snapshot.json | 290 + control-plane/drizzle/meta/0023_snapshot.json | 296 + control-plane/drizzle/meta/0024_snapshot.json | 296 + control-plane/drizzle/meta/0025_snapshot.json | 296 + control-plane/drizzle/meta/0026_snapshot.json | 400 + control-plane/drizzle/meta/0027_snapshot.json | 400 + control-plane/drizzle/meta/0028_snapshot.json | 400 + control-plane/drizzle/meta/0029_snapshot.json | 400 + control-plane/drizzle/meta/0030_snapshot.json | 407 + control-plane/drizzle/meta/0031_snapshot.json | 475 + control-plane/drizzle/meta/0032_snapshot.json | 503 + control-plane/drizzle/meta/0033_snapshot.json | 510 + control-plane/drizzle/meta/0034_snapshot.json | 522 + control-plane/drizzle/meta/0035_snapshot.json | 534 + control-plane/drizzle/meta/0036_snapshot.json | 589 + control-plane/drizzle/meta/0037_snapshot.json | 608 + control-plane/drizzle/meta/0038_snapshot.json | 615 + control-plane/drizzle/meta/0039_snapshot.json | 621 + control-plane/drizzle/meta/0040_snapshot.json | 628 + control-plane/drizzle/meta/0041_snapshot.json | 638 + control-plane/drizzle/meta/0042_snapshot.json | 686 + control-plane/drizzle/meta/0043_snapshot.json | 755 + control-plane/drizzle/meta/0044_snapshot.json | 749 + control-plane/drizzle/meta/0045_snapshot.json | 750 + control-plane/drizzle/meta/0046_snapshot.json | 793 + control-plane/drizzle/meta/0047_snapshot.json | 795 + control-plane/drizzle/meta/0048_snapshot.json | 793 + control-plane/drizzle/meta/0049_snapshot.json | 851 + control-plane/drizzle/meta/0050_snapshot.json | 912 + control-plane/drizzle/meta/0051_snapshot.json | 920 + control-plane/drizzle/meta/0052_snapshot.json | 926 + control-plane/drizzle/meta/0053_snapshot.json | 926 + control-plane/drizzle/meta/0054_snapshot.json | 932 + control-plane/drizzle/meta/0055_snapshot.json | 982 + control-plane/drizzle/meta/0056_snapshot.json | 988 + control-plane/drizzle/meta/0057_snapshot.json | 1052 + control-plane/drizzle/meta/0058_snapshot.json | 1129 + control-plane/drizzle/meta/0059_snapshot.json | 1131 + control-plane/drizzle/meta/0060_snapshot.json | 1141 + control-plane/drizzle/meta/0061_snapshot.json | 1147 + control-plane/drizzle/meta/0062_snapshot.json | 1141 + control-plane/drizzle/meta/0063_snapshot.json | 842 + control-plane/drizzle/meta/0064_snapshot.json | 848 + control-plane/drizzle/meta/0065_snapshot.json | 899 + control-plane/drizzle/meta/0066_snapshot.json | 923 + control-plane/drizzle/meta/0067_snapshot.json | 929 + control-plane/drizzle/meta/0068_snapshot.json | 941 + control-plane/drizzle/meta/0069_snapshot.json | 941 + control-plane/drizzle/meta/0070_snapshot.json | 941 + control-plane/drizzle/meta/0071_snapshot.json | 941 + control-plane/drizzle/meta/0072_snapshot.json | 1025 + control-plane/drizzle/meta/0073_snapshot.json | 1031 + control-plane/drizzle/meta/0074_snapshot.json | 1055 + control-plane/drizzle/meta/0075_snapshot.json | 1061 + control-plane/drizzle/meta/0076_snapshot.json | 1067 + control-plane/drizzle/meta/0077_snapshot.json | 1073 + control-plane/drizzle/meta/0078_snapshot.json | 973 + control-plane/drizzle/meta/0079_snapshot.json | 967 + control-plane/drizzle/meta/0080_snapshot.json | 1121 + control-plane/drizzle/meta/0081_snapshot.json | 1121 + control-plane/drizzle/meta/0082_snapshot.json | 1182 + control-plane/drizzle/meta/0083_snapshot.json | 1188 + control-plane/drizzle/meta/0084_snapshot.json | 1263 + control-plane/drizzle/meta/0085_snapshot.json | 1264 + control-plane/drizzle/meta/0086_snapshot.json | 1264 + control-plane/drizzle/meta/0087_snapshot.json | 1278 + control-plane/drizzle/meta/0088_snapshot.json | 1285 + control-plane/drizzle/meta/0089_snapshot.json | 1297 + control-plane/drizzle/meta/0090_snapshot.json | 1373 + control-plane/drizzle/meta/0091_snapshot.json | 1379 + control-plane/drizzle/meta/0092_snapshot.json | 1391 + control-plane/drizzle/meta/0093_snapshot.json | 1315 + control-plane/drizzle/meta/0094_snapshot.json | 1322 + control-plane/drizzle/meta/0095_snapshot.json | 1330 + control-plane/drizzle/meta/0096_snapshot.json | 1170 + control-plane/drizzle/meta/0097_snapshot.json | 1177 + control-plane/drizzle/meta/0098_snapshot.json | 1248 + control-plane/drizzle/meta/0099_snapshot.json | 1249 + control-plane/drizzle/meta/0100_snapshot.json | 1249 + control-plane/drizzle/meta/0101_snapshot.json | 1255 + control-plane/drizzle/meta/0102_snapshot.json | 1261 + control-plane/drizzle/meta/0103_snapshot.json | 1255 + control-plane/drizzle/meta/0104_snapshot.json | 1261 + control-plane/drizzle/meta/0105_snapshot.json | 1261 + control-plane/drizzle/meta/0106_snapshot.json | 1267 + control-plane/drizzle/meta/0107_snapshot.json | 1288 + control-plane/drizzle/meta/0108_snapshot.json | 1295 + control-plane/drizzle/meta/0109_snapshot.json | 1301 + control-plane/drizzle/meta/0110_snapshot.json | 1307 + control-plane/drizzle/meta/0111_snapshot.json | 1364 + control-plane/drizzle/meta/0112_snapshot.json | 1371 + control-plane/drizzle/meta/0113_snapshot.json | 1364 + control-plane/drizzle/meta/0114_snapshot.json | 1282 + control-plane/drizzle/meta/0115_snapshot.json | 1275 + control-plane/drizzle/meta/0116_snapshot.json | 1212 + control-plane/drizzle/meta/0117_snapshot.json | 966 + control-plane/drizzle/meta/0118_snapshot.json | 972 + control-plane/drizzle/meta/0119_snapshot.json | 972 + control-plane/drizzle/meta/0120_snapshot.json | 1014 + control-plane/drizzle/meta/0121_snapshot.json | 1015 + control-plane/drizzle/meta/0122_snapshot.json | 1050 + control-plane/drizzle/meta/0123_snapshot.json | 1015 + control-plane/drizzle/meta/0124_snapshot.json | 1022 + control-plane/drizzle/meta/0125_snapshot.json | 1029 + control-plane/drizzle/meta/0126_snapshot.json | 1036 + control-plane/drizzle/meta/0127_snapshot.json | 1078 + control-plane/drizzle/meta/0128_snapshot.json | 1084 + control-plane/drizzle/meta/0129_snapshot.json | 1096 + control-plane/drizzle/meta/0130_snapshot.json | 1102 + control-plane/drizzle/meta/0131_snapshot.json | 1109 + control-plane/drizzle/meta/0132_snapshot.json | 1109 + control-plane/drizzle/meta/0133_snapshot.json | 1131 + control-plane/drizzle/meta/0134_snapshot.json | 1119 + control-plane/drizzle/meta/0135_snapshot.json | 1119 + control-plane/drizzle/meta/0136_snapshot.json | 1127 + control-plane/drizzle/meta/0137_snapshot.json | 1115 + control-plane/drizzle/meta/0138_snapshot.json | 1217 + control-plane/drizzle/meta/0139_snapshot.json | 1223 + control-plane/drizzle/meta/0140_snapshot.json | 1320 + control-plane/drizzle/meta/0141_snapshot.json | 1326 + control-plane/drizzle/meta/0142_snapshot.json | 1332 + control-plane/drizzle/meta/0143_snapshot.json | 1413 ++ control-plane/drizzle/meta/0144_snapshot.json | 1419 ++ control-plane/drizzle/meta/0145_snapshot.json | 1529 ++ control-plane/drizzle/meta/0146_snapshot.json | 1675 ++ control-plane/drizzle/meta/0147_snapshot.json | 1681 ++ control-plane/drizzle/meta/0148_snapshot.json | 1682 ++ control-plane/drizzle/meta/0149_snapshot.json | 1682 ++ control-plane/drizzle/meta/0150_snapshot.json | 1669 ++ control-plane/drizzle/meta/0151_snapshot.json | 1663 ++ control-plane/drizzle/meta/0152_snapshot.json | 1669 ++ control-plane/drizzle/meta/0153_snapshot.json | 1669 ++ control-plane/drizzle/meta/0154_snapshot.json | 1669 ++ control-plane/drizzle/meta/0155_snapshot.json | 1726 ++ control-plane/drizzle/meta/0156_snapshot.json | 1765 ++ control-plane/drizzle/meta/0157_snapshot.json | 1885 ++ control-plane/drizzle/meta/0158_snapshot.json | 1892 ++ control-plane/drizzle/meta/0159_snapshot.json | 1898 ++ control-plane/drizzle/meta/0160_snapshot.json | 1905 ++ control-plane/drizzle/meta/0161_snapshot.json | 1898 ++ control-plane/drizzle/meta/0162_snapshot.json | 1904 ++ control-plane/drizzle/meta/0163_snapshot.json | 1905 ++ control-plane/drizzle/meta/0164_snapshot.json | 1933 ++ control-plane/drizzle/meta/0165_snapshot.json | 1835 ++ control-plane/drizzle/meta/0166_snapshot.json | 1744 ++ control-plane/drizzle/meta/0167_snapshot.json | 1744 ++ control-plane/drizzle/meta/0168_snapshot.json | 1744 ++ control-plane/drizzle/meta/0169_snapshot.json | 1773 ++ control-plane/drizzle/meta/0170_snapshot.json | 1752 ++ control-plane/drizzle/meta/0171_snapshot.json | 1758 ++ control-plane/drizzle/meta/0172_snapshot.json | 1765 ++ control-plane/drizzle/meta/0173_snapshot.json | 1772 ++ control-plane/drizzle/meta/0174_snapshot.json | 1778 ++ control-plane/drizzle/meta/0175_snapshot.json | 1784 ++ control-plane/drizzle/meta/0176_snapshot.json | 1790 ++ control-plane/drizzle/meta/0177_snapshot.json | 1796 ++ control-plane/drizzle/meta/0178_snapshot.json | 1796 ++ control-plane/drizzle/meta/0179_snapshot.json | 1796 ++ control-plane/drizzle/meta/0180_snapshot.json | 1802 ++ control-plane/drizzle/meta/0181_snapshot.json | 1802 ++ control-plane/drizzle/meta/0182_snapshot.json | 1808 ++ control-plane/drizzle/meta/0183_snapshot.json | 1872 ++ control-plane/drizzle/meta/0184_snapshot.json | 1872 ++ control-plane/drizzle/meta/0185_snapshot.json | 1871 ++ control-plane/drizzle/meta/0186_snapshot.json | 1885 ++ control-plane/drizzle/meta/0187_snapshot.json | 1898 ++ control-plane/drizzle/meta/_journal.json | 1315 + control-plane/internal.md | 9 + control-plane/jest.config.ts | 8 + control-plane/package-lock.json | 21148 ++++++++++++++++ control-plane/package.json | 87 + control-plane/src/index.ts | 197 + control-plane/src/modules/analytics/index.ts | 116 + .../src/modules/auth/api-secret.test.ts | 45 + control-plane/src/modules/auth/api-secret.ts | 133 + control-plane/src/modules/auth/auth.test.ts | 795 + control-plane/src/modules/auth/auth.ts | 510 + control-plane/src/modules/auth/clerk-token.ts | 88 + .../src/modules/auth/clert-token.test.ts | 34 + .../src/modules/auth/customer-auth.ts | 67 + control-plane/src/modules/auth/router.ts | 110 + control-plane/src/modules/blobs.ts | 107 + control-plane/src/modules/calls/router.ts | 294 + control-plane/src/modules/cluster-export.ts | 92 + control-plane/src/modules/cluster.ts | 90 + control-plane/src/modules/clusters.test.ts | 68 + control-plane/src/modules/contract.ts | 1525 ++ control-plane/src/modules/cron.ts | 43 + .../src/modules/customer-telemetry.ts | 247 + control-plane/src/modules/data.ts | 730 + .../embeddings/bedrock-cohere-embeddings.ts | 100 + .../src/modules/embeddings/embeddings.test.ts | 77 + .../src/modules/embeddings/embeddings.ts | 301 + control-plane/src/modules/flagsmith.ts | 10 + control-plane/src/modules/health.ts | 8 + .../integrations/integration-events.ts | 36 + .../src/modules/integrations/integrations.ts | 74 + .../src/modules/integrations/langfuse.ts | 135 + .../src/modules/integrations/router.ts | 55 + .../src/modules/integrations/toolhouse.ts | 223 + control-plane/src/modules/jobs/create-job.ts | 286 + control-plane/src/modules/jobs/external.ts | 75 + control-plane/src/modules/jobs/jobs.test.ts | 426 + control-plane/src/modules/jobs/jobs.ts | 411 + .../src/modules/jobs/persist-result.test.ts | 229 + .../src/modules/jobs/persist-result.ts | 348 + .../modules/knowledge/knowledgebase.test.ts | 69 + .../src/modules/knowledge/knowledgebase.ts | 134 + .../modules/knowledge/learnings.ai.test.ts | 190 + .../src/modules/knowledge/learnings.ts | 170 + control-plane/src/modules/knowledge/queues.ts | 79 + control-plane/src/modules/machines.test.ts | 69 + control-plane/src/modules/machines.ts | 71 + control-plane/src/modules/machines/router.ts | 94 + control-plane/src/modules/management.ts | 233 + .../src/modules/models/index.test.ts | 81 + control-plane/src/modules/models/index.ts | 406 + control-plane/src/modules/models/routing.ts | 215 + control-plane/src/modules/names.ts | 171 + .../src/modules/observability/events.test.ts | 123 + .../src/modules/observability/events.ts | 386 + .../src/modules/observability/hyperdx.ts | 43 + .../src/modules/observability/logger.ts | 73 + .../src/modules/observability/rollbar.ts | 47 + .../src/modules/observability/tracer.ts | 76 + control-plane/src/modules/packer.ts | 21 + control-plane/src/modules/posthog.ts | 8 + .../src/modules/prompt-templates.test.ts | 229 + control-plane/src/modules/prompt-templates.ts | 461 + control-plane/src/modules/prompts.test.ts | 55 + control-plane/src/modules/prompts.ts | 38 + .../src/modules/rate-limiter.test.ts | 135 + control-plane/src/modules/rate-limiter.ts | 58 + control-plane/src/modules/redis.ts | 16 + control-plane/src/modules/result-keys.test.ts | 103 + control-plane/src/modules/result-keys.ts | 66 + control-plane/src/modules/router.test.ts | 27 + control-plane/src/modules/router.ts | 928 + .../src/modules/service-definitions.test.ts | 283 + .../src/modules/service-definitions.ts | 468 + control-plane/src/modules/service-metadata.ts | 63 + control-plane/src/modules/sqs.ts | 84 + control-plane/src/modules/test/util.ts | 27 + control-plane/src/modules/tool-metadata.ts | 107 + control-plane/src/modules/util.test.ts | 39 + control-plane/src/modules/util.ts | 30 + .../src/modules/versioned-entities.ts | 93 + control-plane/src/modules/versioned-text.ts | 30 + .../modules/workflows/agent/agent.ai.test.ts | 432 + .../src/modules/workflows/agent/agent.ts | 70 + .../workflows/agent/nodes/edges.test.ts | 315 + .../modules/workflows/agent/nodes/edges.ts | 96 + .../workflows/agent/nodes/model-call.test.ts | 411 + .../workflows/agent/nodes/model-call.ts | 444 + .../workflows/agent/nodes/tool-call.test.ts | 335 + .../workflows/agent/nodes/tool-call.ts | 415 + .../workflows/agent/nodes/tool-parser.test.ts | 422 + .../workflows/agent/nodes/tool-parser.ts | 32 + .../src/modules/workflows/agent/run.test.ts | 140 + .../src/modules/workflows/agent/run.ts | 447 + .../src/modules/workflows/agent/state.ts | 84 + .../src/modules/workflows/agent/summarizer.ts | 115 + .../workflows/agent/tools/functions.ts | 239 + .../agent/tools/knowledge-artifacts.ts | 77 + .../workflows/agent/tools/mock-function.ts | 58 + .../src/modules/workflows/agent/utils.test.ts | 9 + .../src/modules/workflows/agent/utils.ts | 39 + .../src/modules/workflows/metadata.test.ts | 36 + .../src/modules/workflows/metadata.ts | 73 + control-plane/src/modules/workflows/notify.ts | 74 + control-plane/src/modules/workflows/queues.ts | 156 + control-plane/src/modules/workflows/router.ts | 455 + .../src/modules/workflows/summarization.ts | 55 + .../modules/workflows/workflow-messages.ts | 550 + .../src/modules/workflows/workflows.test.ts | 200 + .../src/modules/workflows/workflows.ts | 722 + control-plane/src/utilities/cache.ts | 21 + control-plane/src/utilities/constants.ts | 3 + control-plane/src/utilities/env.ts | 125 + control-plane/src/utilities/errors.ts | 115 + control-plane/src/utilities/migrate.ts | 27 + control-plane/src/utilities/run-migrate.ts | 11 + control-plane/src/utilities/safe-parse.ts | 10 + control-plane/tsconfig.json | 19 + 655 files changed, 280257 insertions(+) create mode 100644 app/.dockerignore create mode 100644 app/.eslintrc.json create mode 100644 app/Dockerfile.dev create mode 100644 app/README.md create mode 100644 app/app/cli-auth/page.tsx create mode 100644 app/app/clusters/[clusterId]/configs/[promptId]/edit/page.tsx create mode 100644 app/app/clusters/[clusterId]/configs/global/page.tsx create mode 100644 app/app/clusters/[clusterId]/configs/layout.tsx create mode 100644 app/app/clusters/[clusterId]/configs/new/page.tsx create mode 100644 app/app/clusters/[clusterId]/configs/page.tsx create mode 100644 app/app/clusters/[clusterId]/integrations/langfuse/page.tsx create mode 100644 app/app/clusters/[clusterId]/integrations/layout.tsx create mode 100644 app/app/clusters/[clusterId]/integrations/page.tsx create mode 100644 app/app/clusters/[clusterId]/integrations/toolhouse/page.tsx create mode 100644 app/app/clusters/[clusterId]/knowledge/[artifactId]/edit/page.tsx create mode 100644 app/app/clusters/[clusterId]/knowledge/layout.tsx create mode 100644 app/app/clusters/[clusterId]/knowledge/new/page.tsx create mode 100644 app/app/clusters/[clusterId]/knowledge/page.tsx create mode 100644 app/app/clusters/[clusterId]/layout.tsx create mode 100644 app/app/clusters/[clusterId]/page.tsx create mode 100644 app/app/clusters/[clusterId]/runs/[runId]/page.tsx create mode 100644 app/app/clusters/[clusterId]/runs/layout.tsx create mode 100644 app/app/clusters/[clusterId]/runs/page.tsx create mode 100644 app/app/clusters/[clusterId]/settings/api-keys/page.tsx create mode 100644 app/app/clusters/[clusterId]/settings/danger/page.tsx create mode 100644 app/app/clusters/[clusterId]/settings/details/page.tsx create mode 100644 app/app/clusters/[clusterId]/settings/layout.tsx create mode 100644 app/app/clusters/[clusterId]/settings/page.tsx create mode 100644 app/app/clusters/[clusterId]/usage/page.tsx create mode 100644 app/app/clusters/layout.tsx create mode 100644 app/app/clusters/page.tsx create mode 100644 app/app/favicon.ico create mode 100644 app/app/favicon.ico- create mode 100644 app/app/globals.css create mode 100644 app/app/layout.tsx create mode 100644 app/app/page.tsx create mode 100644 app/app/providers.tsx create mode 100644 app/app/switch-org/page.tsx create mode 100644 app/client/client.ts create mode 100644 app/client/contract.ts create mode 100644 app/components.json create mode 100644 app/components/FakeProgress.tsx create mode 100644 app/components/KnowledgeArtifactForm.tsx create mode 100644 app/components/OrgList.tsx create mode 100644 app/components/PromptMetricsCharts.tsx create mode 100644 app/components/ThinkingIndicator.tsx create mode 100644 app/components/WorkflowList.tsx create mode 100644 app/components/api-keys.tsx create mode 100644 app/components/breadcrumbs.tsx create mode 100644 app/components/bug-report-dialog.tsx create mode 100644 app/components/chat/ResultTable.css create mode 100644 app/components/chat/Summarizable.tsx create mode 100644 app/components/chat/ToolContextButton.tsx create mode 100644 app/components/chat/ai-message.tsx create mode 100644 app/components/chat/blob.tsx create mode 100644 app/components/chat/event-indicator.tsx create mode 100644 app/components/chat/function-call.tsx create mode 100644 app/components/chat/human-message.tsx create mode 100644 app/components/chat/input-fields.tsx create mode 100644 app/components/chat/prompt-template-form.tsx create mode 100644 app/components/chat/prompt-textarea.tsx create mode 100644 app/components/chat/run-config.tsx create mode 100644 app/components/chat/sdk-commands.tsx create mode 100644 app/components/chat/structured-output-editor.tsx create mode 100644 app/components/chat/template-mesage.tsx create mode 100644 app/components/chat/template-search.tsx create mode 100644 app/components/chat/tool-input.tsx create mode 100644 app/components/chat/typable.tsx create mode 100644 app/components/chat/workflow-event.tsx create mode 100644 app/components/circles.tsx create mode 100644 app/components/cluster-card.tsx create mode 100644 app/components/cluster-details.tsx create mode 100644 app/components/cluster-health-plane.tsx create mode 100644 app/components/cluster-list.tsx create mode 100644 app/components/copy-button.tsx create mode 100644 app/components/create-api-key.tsx create mode 100644 app/components/create-cluster-button.tsx create mode 100644 app/components/crisp-chat.tsx create mode 100644 app/components/debug-event.tsx create mode 100644 app/components/error-display.tsx create mode 100644 app/components/events-overlay.tsx create mode 100644 app/components/fetch-rerender-error.example.md create mode 100644 app/components/header.tsx create mode 100644 app/components/instructions-editor.css create mode 100644 app/components/instructions-editor.tsx create mode 100644 app/components/job-references.tsx create mode 100644 app/components/json-form.tsx create mode 100644 app/components/knowledge-quickstart.tsx create mode 100644 app/components/loading.tsx create mode 100644 app/components/logo-2.png create mode 100644 app/components/logo.png create mode 100644 app/components/markdown-editor.tsx create mode 100644 app/components/mdxeditor.css create mode 100644 app/components/posthog-pageview.tsx create mode 100644 app/components/posthog-user.tsx create mode 100644 app/components/read-only-json.tsx create mode 100644 app/components/rollbar-user.tsx create mode 100644 app/components/server-connection-pane.tsx create mode 100644 app/components/service-details-pane.tsx create mode 100644 app/components/services-overview.tsx create mode 100644 app/components/services-quickstart.tsx create mode 100644 app/components/ui/accordion.tsx create mode 100644 app/components/ui/alert-dialog.tsx create mode 100644 app/components/ui/alert.tsx create mode 100644 app/components/ui/badge.tsx create mode 100644 app/components/ui/breadcrumb.tsx create mode 100644 app/components/ui/button.tsx create mode 100644 app/components/ui/card.tsx create mode 100644 app/components/ui/chart.tsx create mode 100644 app/components/ui/checkbox.tsx create mode 100644 app/components/ui/collapsible.tsx create mode 100644 app/components/ui/command.tsx create mode 100644 app/components/ui/data-table.tsx create mode 100644 app/components/ui/dialog.tsx create mode 100644 app/components/ui/drawer.tsx create mode 100644 app/components/ui/dropdown-menu.tsx create mode 100644 app/components/ui/form.tsx create mode 100644 app/components/ui/input.tsx create mode 100644 app/components/ui/label.tsx create mode 100644 app/components/ui/menubar.tsx create mode 100644 app/components/ui/multiselect.tsx create mode 100644 app/components/ui/popover.tsx create mode 100644 app/components/ui/progress.tsx create mode 100644 app/components/ui/scroll-area.tsx create mode 100644 app/components/ui/select.tsx create mode 100644 app/components/ui/sheet.tsx create mode 100644 app/components/ui/skeleton.tsx create mode 100644 app/components/ui/switch.tsx create mode 100644 app/components/ui/table.tsx create mode 100644 app/components/ui/tabs.tsx create mode 100644 app/components/ui/textarea.tsx create mode 100644 app/components/ui/toggle-group.tsx create mode 100644 app/components/ui/toggle.tsx create mode 100644 app/components/ui/tooltip.tsx create mode 100644 app/components/workflow-tab.tsx create mode 100644 app/components/workflow.tsx create mode 100644 app/lib/auth.ts create mode 100644 app/lib/colorize-json.ts create mode 100644 app/lib/encryption.ts create mode 100644 app/lib/types.ts create mode 100644 app/lib/use-authenticated-client.ts create mode 100644 app/lib/utils.ts create mode 100644 app/middleware.ts create mode 100644 app/next.config.mjs create mode 100644 app/package-lock.json create mode 100644 app/package.json create mode 100644 app/pages/api/health.ts create mode 100644 app/postcss.config.mjs create mode 100644 app/styles/button-animations.css create mode 100644 app/tailwind.config.ts create mode 100644 app/tsconfig.json create mode 100644 control-plane/.dockerignore create mode 100644 control-plane/.eslintrc create mode 100644 control-plane/@types/fastify/index.d.ts create mode 100644 control-plane/Dockerfile.dev create mode 100644 control-plane/README.md create mode 100644 control-plane/babel.config.js create mode 100644 control-plane/docker-compose.dev.yml create mode 100644 control-plane/drizzle.config.ts create mode 100644 control-plane/drizzle/0000_odd_tattoo.sql create mode 100644 control-plane/drizzle/0001_tense_dreaming_celestial.sql create mode 100644 control-plane/drizzle/0002_steady_korath.sql create mode 100644 control-plane/drizzle/0003_living_captain_america.sql create mode 100644 control-plane/drizzle/0004_confused_goliath.sql create mode 100644 control-plane/drizzle/0005_overconfident_hex.sql create mode 100644 control-plane/drizzle/0006_ambiguous_wild_pack.sql create mode 100644 control-plane/drizzle/0007_icy_the_hand.sql create mode 100644 control-plane/drizzle/0008_omniscient_mongu.sql create mode 100644 control-plane/drizzle/0009_cuddly_medusa.sql create mode 100644 control-plane/drizzle/0010_curious_amphibian.sql create mode 100644 control-plane/drizzle/0011_thin_preak.sql create mode 100644 control-plane/drizzle/0012_manual_make.sql create mode 100644 control-plane/drizzle/0013_bitter_lily_hollister.sql create mode 100644 control-plane/drizzle/0014_kind_mercury.sql create mode 100644 control-plane/drizzle/0015_flimsy_microbe.sql create mode 100644 control-plane/drizzle/0016_unique_wallflower.sql create mode 100644 control-plane/drizzle/0017_purple_captain_stacy.sql create mode 100644 control-plane/drizzle/0018_spooky_sasquatch.sql create mode 100644 control-plane/drizzle/0019_early_silver_sable.sql create mode 100644 control-plane/drizzle/0020_third_lockjaw.sql create mode 100644 control-plane/drizzle/0021_brave_eternals.sql create mode 100644 control-plane/drizzle/0022_bizarre_princess_powerful.sql create mode 100644 control-plane/drizzle/0023_lazy_dakota_north.sql create mode 100644 control-plane/drizzle/0024_thin_black_bolt.sql create mode 100644 control-plane/drizzle/0025_hot_shinobi_shaw.sql create mode 100644 control-plane/drizzle/0026_freezing_clint_barton.sql create mode 100644 control-plane/drizzle/0027_lyrical_ken_ellis.sql create mode 100644 control-plane/drizzle/0028_parallel_karen_page.sql create mode 100644 control-plane/drizzle/0029_sad_thunderbird.sql create mode 100644 control-plane/drizzle/0030_omniscient_jamie_braddock.sql create mode 100644 control-plane/drizzle/0031_misty_slipstream.sql create mode 100644 control-plane/drizzle/0032_clumsy_gressill.sql create mode 100644 control-plane/drizzle/0033_high_komodo.sql create mode 100644 control-plane/drizzle/0034_real_big_bertha.sql create mode 100644 control-plane/drizzle/0035_eminent_fantastic_four.sql create mode 100644 control-plane/drizzle/0036_ambiguous_human_robot.sql create mode 100644 control-plane/drizzle/0037_empty_molecule_man.sql create mode 100644 control-plane/drizzle/0038_woozy_tiger_shark.sql create mode 100644 control-plane/drizzle/0039_puzzling_vampiro.sql create mode 100644 control-plane/drizzle/0040_mean_jazinda.sql create mode 100644 control-plane/drizzle/0041_youthful_steve_rogers.sql create mode 100644 control-plane/drizzle/0042_kind_lester.sql create mode 100644 control-plane/drizzle/0043_closed_weapon_omega.sql create mode 100644 control-plane/drizzle/0044_fancy_landau.sql create mode 100644 control-plane/drizzle/0045_icy_kid_colt.sql create mode 100644 control-plane/drizzle/0046_needy_brood.sql create mode 100644 control-plane/drizzle/0047_certain_penance.sql create mode 100644 control-plane/drizzle/0048_awesome_joystick.sql create mode 100644 control-plane/drizzle/0049_gray_ben_grimm.sql create mode 100644 control-plane/drizzle/0050_slimy_hulk.sql create mode 100644 control-plane/drizzle/0051_loving_phil_sheldon.sql create mode 100644 control-plane/drizzle/0052_swift_microbe.sql create mode 100644 control-plane/drizzle/0053_broken_zaran.sql create mode 100644 control-plane/drizzle/0054_graceful_mentallo.sql create mode 100644 control-plane/drizzle/0055_condemned_doomsday.sql create mode 100644 control-plane/drizzle/0056_chief_havok.sql create mode 100644 control-plane/drizzle/0057_ambiguous_firebird.sql create mode 100644 control-plane/drizzle/0058_bumpy_radioactive_man.sql create mode 100644 control-plane/drizzle/0059_misty_shaman.sql create mode 100644 control-plane/drizzle/0060_normal_midnight.sql create mode 100644 control-plane/drizzle/0061_nervous_triathlon.sql create mode 100644 control-plane/drizzle/0062_wide_warpath.sql create mode 100644 control-plane/drizzle/0063_high_lockjaw.sql create mode 100644 control-plane/drizzle/0064_sweet_silverclaw.sql create mode 100644 control-plane/drizzle/0065_fast_oracle.sql create mode 100644 control-plane/drizzle/0066_fearless_storm.sql create mode 100644 control-plane/drizzle/0067_outstanding_deadpool.sql create mode 100644 control-plane/drizzle/0068_tranquil_deadpool.sql create mode 100644 control-plane/drizzle/0069_sudden_longshot.sql create mode 100644 control-plane/drizzle/0070_real_wraith.sql create mode 100644 control-plane/drizzle/0071_tidy_jimmy_woo.sql create mode 100644 control-plane/drizzle/0072_right_slipstream.sql create mode 100644 control-plane/drizzle/0073_nervous_chamber.sql create mode 100644 control-plane/drizzle/0074_ancient_roxanne_simpson.sql create mode 100644 control-plane/drizzle/0075_outgoing_christian_walker.sql create mode 100644 control-plane/drizzle/0076_demonic_captain_flint.sql create mode 100644 control-plane/drizzle/0077_bitter_ulik.sql create mode 100644 control-plane/drizzle/0078_wonderful_penance.sql create mode 100644 control-plane/drizzle/0079_reflective_mathemanic.sql create mode 100644 control-plane/drizzle/0080_simple_jimmy_woo.sql create mode 100644 control-plane/drizzle/0081_spicy_spencer_smythe.sql create mode 100644 control-plane/drizzle/0082_slimy_kronos.sql create mode 100644 control-plane/drizzle/0083_natural_rhino.sql create mode 100644 control-plane/drizzle/0084_red_terrax.sql create mode 100644 control-plane/drizzle/0085_conscious_purifiers.sql create mode 100644 control-plane/drizzle/0086_ambiguous_swarm.sql create mode 100644 control-plane/drizzle/0087_simple_stone_men.sql create mode 100644 control-plane/drizzle/0088_simple_longshot.sql create mode 100644 control-plane/drizzle/0089_amazing_vargas.sql create mode 100644 control-plane/drizzle/0090_ambitious_chimera.sql create mode 100644 control-plane/drizzle/0091_living_the_professor.sql create mode 100644 control-plane/drizzle/0092_overrated_sunfire.sql create mode 100644 control-plane/drizzle/0093_bumpy_skreet.sql create mode 100644 control-plane/drizzle/0094_complex_clint_barton.sql create mode 100644 control-plane/drizzle/0095_daffy_king_cobra.sql create mode 100644 control-plane/drizzle/0096_romantic_namorita.sql create mode 100644 control-plane/drizzle/0097_cool_pyro.sql create mode 100644 control-plane/drizzle/0098_gorgeous_hellion.sql create mode 100644 control-plane/drizzle/0099_clever_gamora.sql create mode 100644 control-plane/drizzle/0100_fuzzy_redwing.sql create mode 100644 control-plane/drizzle/0101_magical_zarek.sql create mode 100644 control-plane/drizzle/0102_massive_exiles.sql create mode 100644 control-plane/drizzle/0103_nervous_kid_colt.sql create mode 100644 control-plane/drizzle/0104_salty_ultron.sql create mode 100644 control-plane/drizzle/0105_bouncy_wallow.sql create mode 100644 control-plane/drizzle/0106_happy_moondragon.sql create mode 100644 control-plane/drizzle/0107_hesitant_thaddeus_ross.sql create mode 100644 control-plane/drizzle/0108_little_rhino.sql create mode 100644 control-plane/drizzle/0109_majestic_otto_octavius.sql create mode 100644 control-plane/drizzle/0110_round_captain_britain.sql create mode 100644 control-plane/drizzle/0111_sturdy_black_widow.sql create mode 100644 control-plane/drizzle/0112_funny_red_ghost.sql create mode 100644 control-plane/drizzle/0113_overjoyed_scream.sql create mode 100644 control-plane/drizzle/0114_bright_mesmero.sql create mode 100644 control-plane/drizzle/0115_lonely_talon.sql create mode 100644 control-plane/drizzle/0116_far_justice.sql create mode 100644 control-plane/drizzle/0117_perfect_frightful_four.sql create mode 100644 control-plane/drizzle/0118_red_garia.sql create mode 100644 control-plane/drizzle/0119_sour_tinkerer.sql create mode 100644 control-plane/drizzle/0120_fearless_krista_starr.sql create mode 100644 control-plane/drizzle/0121_silky_wolverine.sql create mode 100644 control-plane/drizzle/0122_nice_black_tarantula.sql create mode 100644 control-plane/drizzle/0123_woozy_squirrel_girl.sql create mode 100644 control-plane/drizzle/0124_careless_harpoon.sql create mode 100644 control-plane/drizzle/0125_remarkable_cable.sql create mode 100644 control-plane/drizzle/0126_tiresome_glorian.sql create mode 100644 control-plane/drizzle/0127_illegal_james_howlett.sql create mode 100644 control-plane/drizzle/0128_tricky_steel_serpent.sql create mode 100644 control-plane/drizzle/0129_military_crystal.sql create mode 100644 control-plane/drizzle/0130_brief_ben_parker.sql create mode 100644 control-plane/drizzle/0131_regular_demogoblin.sql create mode 100644 control-plane/drizzle/0132_elite_lady_bullseye.sql create mode 100644 control-plane/drizzle/0133_nice_luckman.sql create mode 100644 control-plane/drizzle/0134_tiny_anita_blake.sql create mode 100644 control-plane/drizzle/0135_majestic_callisto.sql create mode 100644 control-plane/drizzle/0136_many_nightmare.sql create mode 100644 control-plane/drizzle/0137_remarkable_hardball.sql create mode 100644 control-plane/drizzle/0138_lively_the_leader.sql create mode 100644 control-plane/drizzle/0139_lean_forge.sql create mode 100644 control-plane/drizzle/0140_windy_grim_reaper.sql create mode 100644 control-plane/drizzle/0141_real_hex.sql create mode 100644 control-plane/drizzle/0142_opposite_leo.sql create mode 100644 control-plane/drizzle/0143_overconfident_lady_mastermind.sql create mode 100644 control-plane/drizzle/0144_crazy_shriek.sql create mode 100644 control-plane/drizzle/0145_smart_weapon_omega.sql create mode 100644 control-plane/drizzle/0146_moaning_rattler.sql create mode 100644 control-plane/drizzle/0147_clammy_ulik.sql create mode 100644 control-plane/drizzle/0148_slimy_alex_wilder.sql create mode 100644 control-plane/drizzle/0149_last_nighthawk.sql create mode 100644 control-plane/drizzle/0150_giant_bishop.sql create mode 100644 control-plane/drizzle/0151_careless_romulus.sql create mode 100644 control-plane/drizzle/0152_strong_tomorrow_man.sql create mode 100644 control-plane/drizzle/0153_unique_starhawk.sql create mode 100644 control-plane/drizzle/0154_tiresome_orphan.sql create mode 100644 control-plane/drizzle/0155_lush_shadow_king.sql create mode 100644 control-plane/drizzle/0156_old_justice.sql create mode 100644 control-plane/drizzle/0157_icy_hawkeye.sql create mode 100644 control-plane/drizzle/0158_lush_machine_man.sql create mode 100644 control-plane/drizzle/0159_lazy_quentin_quire.sql create mode 100644 control-plane/drizzle/0159_tranquil_tempest.sql create mode 100644 control-plane/drizzle/0160_breezy_roulette.sql create mode 100644 control-plane/drizzle/0161_jazzy_lucky_pierre.sql create mode 100644 control-plane/drizzle/0162_sour_romulus.sql create mode 100644 control-plane/drizzle/0163_dizzy_ogun.sql create mode 100644 control-plane/drizzle/0164_large_zzzax.sql create mode 100644 control-plane/drizzle/0165_nice_angel.sql create mode 100644 control-plane/drizzle/0166_same_gargoyle.sql create mode 100644 control-plane/drizzle/0167_high_silver_fox.sql create mode 100644 control-plane/drizzle/0168_wet_prima.sql create mode 100644 control-plane/drizzle/0169_modern_big_bertha.sql create mode 100644 control-plane/drizzle/0170_wet_steve_rogers.sql create mode 100644 control-plane/drizzle/0171_wise_bloodaxe.sql create mode 100644 control-plane/drizzle/0172_sweet_jane_foster.sql create mode 100644 control-plane/drizzle/0173_outstanding_silvermane.sql create mode 100644 control-plane/drizzle/0174_careful_silhouette.sql create mode 100644 control-plane/drizzle/0175_clever_cardiac.sql create mode 100644 control-plane/drizzle/0176_loose_wilson_fisk.sql create mode 100644 control-plane/drizzle/0177_bright_machine_man.sql create mode 100644 control-plane/drizzle/0178_thankful_hellcat.sql create mode 100644 control-plane/drizzle/0179_tranquil_mongu.sql create mode 100644 control-plane/drizzle/0180_clumsy_sheva_callister.sql create mode 100644 control-plane/drizzle/0181_oval_shadow_king.sql create mode 100644 control-plane/drizzle/0182_lethal_darkstar.sql create mode 100644 control-plane/drizzle/0183_black_multiple_man.sql create mode 100644 control-plane/drizzle/0184_nervous_jubilee.sql create mode 100644 control-plane/drizzle/0185_many_thunderbolt.sql create mode 100644 control-plane/drizzle/0186_oval_maggott.sql create mode 100644 control-plane/drizzle/0187_sour_black_queen.sql create mode 100644 control-plane/drizzle/meta/0000_snapshot.json create mode 100644 control-plane/drizzle/meta/0001_snapshot.json create mode 100644 control-plane/drizzle/meta/0002_snapshot.json create mode 100644 control-plane/drizzle/meta/0003_snapshot.json create mode 100644 control-plane/drizzle/meta/0004_snapshot.json create mode 100644 control-plane/drizzle/meta/0005_snapshot.json create mode 100644 control-plane/drizzle/meta/0006_snapshot.json create mode 100644 control-plane/drizzle/meta/0007_snapshot.json create mode 100644 control-plane/drizzle/meta/0008_snapshot.json create mode 100644 control-plane/drizzle/meta/0009_snapshot.json create mode 100644 control-plane/drizzle/meta/0010_snapshot.json create mode 100644 control-plane/drizzle/meta/0011_snapshot.json create mode 100644 control-plane/drizzle/meta/0012_snapshot.json create mode 100644 control-plane/drizzle/meta/0013_snapshot.json create mode 100644 control-plane/drizzle/meta/0014_snapshot.json create mode 100644 control-plane/drizzle/meta/0015_snapshot.json create mode 100644 control-plane/drizzle/meta/0016_snapshot.json create mode 100644 control-plane/drizzle/meta/0017_snapshot.json create mode 100644 control-plane/drizzle/meta/0018_snapshot.json create mode 100644 control-plane/drizzle/meta/0019_snapshot.json create mode 100644 control-plane/drizzle/meta/0020_snapshot.json create mode 100644 control-plane/drizzle/meta/0021_snapshot.json create mode 100644 control-plane/drizzle/meta/0022_snapshot.json create mode 100644 control-plane/drizzle/meta/0023_snapshot.json create mode 100644 control-plane/drizzle/meta/0024_snapshot.json create mode 100644 control-plane/drizzle/meta/0025_snapshot.json create mode 100644 control-plane/drizzle/meta/0026_snapshot.json create mode 100644 control-plane/drizzle/meta/0027_snapshot.json create mode 100644 control-plane/drizzle/meta/0028_snapshot.json create mode 100644 control-plane/drizzle/meta/0029_snapshot.json create mode 100644 control-plane/drizzle/meta/0030_snapshot.json create mode 100644 control-plane/drizzle/meta/0031_snapshot.json create mode 100644 control-plane/drizzle/meta/0032_snapshot.json create mode 100644 control-plane/drizzle/meta/0033_snapshot.json create mode 100644 control-plane/drizzle/meta/0034_snapshot.json create mode 100644 control-plane/drizzle/meta/0035_snapshot.json create mode 100644 control-plane/drizzle/meta/0036_snapshot.json create mode 100644 control-plane/drizzle/meta/0037_snapshot.json create mode 100644 control-plane/drizzle/meta/0038_snapshot.json create mode 100644 control-plane/drizzle/meta/0039_snapshot.json create mode 100644 control-plane/drizzle/meta/0040_snapshot.json create mode 100644 control-plane/drizzle/meta/0041_snapshot.json create mode 100644 control-plane/drizzle/meta/0042_snapshot.json create mode 100644 control-plane/drizzle/meta/0043_snapshot.json create mode 100644 control-plane/drizzle/meta/0044_snapshot.json create mode 100644 control-plane/drizzle/meta/0045_snapshot.json create mode 100644 control-plane/drizzle/meta/0046_snapshot.json create mode 100644 control-plane/drizzle/meta/0047_snapshot.json create mode 100644 control-plane/drizzle/meta/0048_snapshot.json create mode 100644 control-plane/drizzle/meta/0049_snapshot.json create mode 100644 control-plane/drizzle/meta/0050_snapshot.json create mode 100644 control-plane/drizzle/meta/0051_snapshot.json create mode 100644 control-plane/drizzle/meta/0052_snapshot.json create mode 100644 control-plane/drizzle/meta/0053_snapshot.json create mode 100644 control-plane/drizzle/meta/0054_snapshot.json create mode 100644 control-plane/drizzle/meta/0055_snapshot.json create mode 100644 control-plane/drizzle/meta/0056_snapshot.json create mode 100644 control-plane/drizzle/meta/0057_snapshot.json create mode 100644 control-plane/drizzle/meta/0058_snapshot.json create mode 100644 control-plane/drizzle/meta/0059_snapshot.json create mode 100644 control-plane/drizzle/meta/0060_snapshot.json create mode 100644 control-plane/drizzle/meta/0061_snapshot.json create mode 100644 control-plane/drizzle/meta/0062_snapshot.json create mode 100644 control-plane/drizzle/meta/0063_snapshot.json create mode 100644 control-plane/drizzle/meta/0064_snapshot.json create mode 100644 control-plane/drizzle/meta/0065_snapshot.json create mode 100644 control-plane/drizzle/meta/0066_snapshot.json create mode 100644 control-plane/drizzle/meta/0067_snapshot.json create mode 100644 control-plane/drizzle/meta/0068_snapshot.json create mode 100644 control-plane/drizzle/meta/0069_snapshot.json create mode 100644 control-plane/drizzle/meta/0070_snapshot.json create mode 100644 control-plane/drizzle/meta/0071_snapshot.json create mode 100644 control-plane/drizzle/meta/0072_snapshot.json create mode 100644 control-plane/drizzle/meta/0073_snapshot.json create mode 100644 control-plane/drizzle/meta/0074_snapshot.json create mode 100644 control-plane/drizzle/meta/0075_snapshot.json create mode 100644 control-plane/drizzle/meta/0076_snapshot.json create mode 100644 control-plane/drizzle/meta/0077_snapshot.json create mode 100644 control-plane/drizzle/meta/0078_snapshot.json create mode 100644 control-plane/drizzle/meta/0079_snapshot.json create mode 100644 control-plane/drizzle/meta/0080_snapshot.json create mode 100644 control-plane/drizzle/meta/0081_snapshot.json create mode 100644 control-plane/drizzle/meta/0082_snapshot.json create mode 100644 control-plane/drizzle/meta/0083_snapshot.json create mode 100644 control-plane/drizzle/meta/0084_snapshot.json create mode 100644 control-plane/drizzle/meta/0085_snapshot.json create mode 100644 control-plane/drizzle/meta/0086_snapshot.json create mode 100644 control-plane/drizzle/meta/0087_snapshot.json create mode 100644 control-plane/drizzle/meta/0088_snapshot.json create mode 100644 control-plane/drizzle/meta/0089_snapshot.json create mode 100644 control-plane/drizzle/meta/0090_snapshot.json create mode 100644 control-plane/drizzle/meta/0091_snapshot.json create mode 100644 control-plane/drizzle/meta/0092_snapshot.json create mode 100644 control-plane/drizzle/meta/0093_snapshot.json create mode 100644 control-plane/drizzle/meta/0094_snapshot.json create mode 100644 control-plane/drizzle/meta/0095_snapshot.json create mode 100644 control-plane/drizzle/meta/0096_snapshot.json create mode 100644 control-plane/drizzle/meta/0097_snapshot.json create mode 100644 control-plane/drizzle/meta/0098_snapshot.json create mode 100644 control-plane/drizzle/meta/0099_snapshot.json create mode 100644 control-plane/drizzle/meta/0100_snapshot.json create mode 100644 control-plane/drizzle/meta/0101_snapshot.json create mode 100644 control-plane/drizzle/meta/0102_snapshot.json create mode 100644 control-plane/drizzle/meta/0103_snapshot.json create mode 100644 control-plane/drizzle/meta/0104_snapshot.json create mode 100644 control-plane/drizzle/meta/0105_snapshot.json create mode 100644 control-plane/drizzle/meta/0106_snapshot.json create mode 100644 control-plane/drizzle/meta/0107_snapshot.json create mode 100644 control-plane/drizzle/meta/0108_snapshot.json create mode 100644 control-plane/drizzle/meta/0109_snapshot.json create mode 100644 control-plane/drizzle/meta/0110_snapshot.json create mode 100644 control-plane/drizzle/meta/0111_snapshot.json create mode 100644 control-plane/drizzle/meta/0112_snapshot.json create mode 100644 control-plane/drizzle/meta/0113_snapshot.json create mode 100644 control-plane/drizzle/meta/0114_snapshot.json create mode 100644 control-plane/drizzle/meta/0115_snapshot.json create mode 100644 control-plane/drizzle/meta/0116_snapshot.json create mode 100644 control-plane/drizzle/meta/0117_snapshot.json create mode 100644 control-plane/drizzle/meta/0118_snapshot.json create mode 100644 control-plane/drizzle/meta/0119_snapshot.json create mode 100644 control-plane/drizzle/meta/0120_snapshot.json create mode 100644 control-plane/drizzle/meta/0121_snapshot.json create mode 100644 control-plane/drizzle/meta/0122_snapshot.json create mode 100644 control-plane/drizzle/meta/0123_snapshot.json create mode 100644 control-plane/drizzle/meta/0124_snapshot.json create mode 100644 control-plane/drizzle/meta/0125_snapshot.json create mode 100644 control-plane/drizzle/meta/0126_snapshot.json create mode 100644 control-plane/drizzle/meta/0127_snapshot.json create mode 100644 control-plane/drizzle/meta/0128_snapshot.json create mode 100644 control-plane/drizzle/meta/0129_snapshot.json create mode 100644 control-plane/drizzle/meta/0130_snapshot.json create mode 100644 control-plane/drizzle/meta/0131_snapshot.json create mode 100644 control-plane/drizzle/meta/0132_snapshot.json create mode 100644 control-plane/drizzle/meta/0133_snapshot.json create mode 100644 control-plane/drizzle/meta/0134_snapshot.json create mode 100644 control-plane/drizzle/meta/0135_snapshot.json create mode 100644 control-plane/drizzle/meta/0136_snapshot.json create mode 100644 control-plane/drizzle/meta/0137_snapshot.json create mode 100644 control-plane/drizzle/meta/0138_snapshot.json create mode 100644 control-plane/drizzle/meta/0139_snapshot.json create mode 100644 control-plane/drizzle/meta/0140_snapshot.json create mode 100644 control-plane/drizzle/meta/0141_snapshot.json create mode 100644 control-plane/drizzle/meta/0142_snapshot.json create mode 100644 control-plane/drizzle/meta/0143_snapshot.json create mode 100644 control-plane/drizzle/meta/0144_snapshot.json create mode 100644 control-plane/drizzle/meta/0145_snapshot.json create mode 100644 control-plane/drizzle/meta/0146_snapshot.json create mode 100644 control-plane/drizzle/meta/0147_snapshot.json create mode 100644 control-plane/drizzle/meta/0148_snapshot.json create mode 100644 control-plane/drizzle/meta/0149_snapshot.json create mode 100644 control-plane/drizzle/meta/0150_snapshot.json create mode 100644 control-plane/drizzle/meta/0151_snapshot.json create mode 100644 control-plane/drizzle/meta/0152_snapshot.json create mode 100644 control-plane/drizzle/meta/0153_snapshot.json create mode 100644 control-plane/drizzle/meta/0154_snapshot.json create mode 100644 control-plane/drizzle/meta/0155_snapshot.json create mode 100644 control-plane/drizzle/meta/0156_snapshot.json create mode 100644 control-plane/drizzle/meta/0157_snapshot.json create mode 100644 control-plane/drizzle/meta/0158_snapshot.json create mode 100644 control-plane/drizzle/meta/0159_snapshot.json create mode 100644 control-plane/drizzle/meta/0160_snapshot.json create mode 100644 control-plane/drizzle/meta/0161_snapshot.json create mode 100644 control-plane/drizzle/meta/0162_snapshot.json create mode 100644 control-plane/drizzle/meta/0163_snapshot.json create mode 100644 control-plane/drizzle/meta/0164_snapshot.json create mode 100644 control-plane/drizzle/meta/0165_snapshot.json create mode 100644 control-plane/drizzle/meta/0166_snapshot.json create mode 100644 control-plane/drizzle/meta/0167_snapshot.json create mode 100644 control-plane/drizzle/meta/0168_snapshot.json create mode 100644 control-plane/drizzle/meta/0169_snapshot.json create mode 100644 control-plane/drizzle/meta/0170_snapshot.json create mode 100644 control-plane/drizzle/meta/0171_snapshot.json create mode 100644 control-plane/drizzle/meta/0172_snapshot.json create mode 100644 control-plane/drizzle/meta/0173_snapshot.json create mode 100644 control-plane/drizzle/meta/0174_snapshot.json create mode 100644 control-plane/drizzle/meta/0175_snapshot.json create mode 100644 control-plane/drizzle/meta/0176_snapshot.json create mode 100644 control-plane/drizzle/meta/0177_snapshot.json create mode 100644 control-plane/drizzle/meta/0178_snapshot.json create mode 100644 control-plane/drizzle/meta/0179_snapshot.json create mode 100644 control-plane/drizzle/meta/0180_snapshot.json create mode 100644 control-plane/drizzle/meta/0181_snapshot.json create mode 100644 control-plane/drizzle/meta/0182_snapshot.json create mode 100644 control-plane/drizzle/meta/0183_snapshot.json create mode 100644 control-plane/drizzle/meta/0184_snapshot.json create mode 100644 control-plane/drizzle/meta/0185_snapshot.json create mode 100644 control-plane/drizzle/meta/0186_snapshot.json create mode 100644 control-plane/drizzle/meta/0187_snapshot.json create mode 100644 control-plane/drizzle/meta/_journal.json create mode 100644 control-plane/internal.md create mode 100644 control-plane/jest.config.ts create mode 100644 control-plane/package-lock.json create mode 100644 control-plane/package.json create mode 100644 control-plane/src/index.ts create mode 100644 control-plane/src/modules/analytics/index.ts create mode 100644 control-plane/src/modules/auth/api-secret.test.ts create mode 100644 control-plane/src/modules/auth/api-secret.ts create mode 100644 control-plane/src/modules/auth/auth.test.ts create mode 100644 control-plane/src/modules/auth/auth.ts create mode 100644 control-plane/src/modules/auth/clerk-token.ts create mode 100644 control-plane/src/modules/auth/clert-token.test.ts create mode 100644 control-plane/src/modules/auth/customer-auth.ts create mode 100644 control-plane/src/modules/auth/router.ts create mode 100644 control-plane/src/modules/blobs.ts create mode 100644 control-plane/src/modules/calls/router.ts create mode 100644 control-plane/src/modules/cluster-export.ts create mode 100644 control-plane/src/modules/cluster.ts create mode 100644 control-plane/src/modules/clusters.test.ts create mode 100644 control-plane/src/modules/contract.ts create mode 100644 control-plane/src/modules/cron.ts create mode 100644 control-plane/src/modules/customer-telemetry.ts create mode 100644 control-plane/src/modules/data.ts create mode 100644 control-plane/src/modules/embeddings/bedrock-cohere-embeddings.ts create mode 100644 control-plane/src/modules/embeddings/embeddings.test.ts create mode 100644 control-plane/src/modules/embeddings/embeddings.ts create mode 100644 control-plane/src/modules/flagsmith.ts create mode 100644 control-plane/src/modules/health.ts create mode 100644 control-plane/src/modules/integrations/integration-events.ts create mode 100644 control-plane/src/modules/integrations/integrations.ts create mode 100644 control-plane/src/modules/integrations/langfuse.ts create mode 100644 control-plane/src/modules/integrations/router.ts create mode 100644 control-plane/src/modules/integrations/toolhouse.ts create mode 100644 control-plane/src/modules/jobs/create-job.ts create mode 100644 control-plane/src/modules/jobs/external.ts create mode 100644 control-plane/src/modules/jobs/jobs.test.ts create mode 100644 control-plane/src/modules/jobs/jobs.ts create mode 100644 control-plane/src/modules/jobs/persist-result.test.ts create mode 100644 control-plane/src/modules/jobs/persist-result.ts create mode 100644 control-plane/src/modules/knowledge/knowledgebase.test.ts create mode 100644 control-plane/src/modules/knowledge/knowledgebase.ts create mode 100644 control-plane/src/modules/knowledge/learnings.ai.test.ts create mode 100644 control-plane/src/modules/knowledge/learnings.ts create mode 100644 control-plane/src/modules/knowledge/queues.ts create mode 100644 control-plane/src/modules/machines.test.ts create mode 100644 control-plane/src/modules/machines.ts create mode 100644 control-plane/src/modules/machines/router.ts create mode 100644 control-plane/src/modules/management.ts create mode 100644 control-plane/src/modules/models/index.test.ts create mode 100644 control-plane/src/modules/models/index.ts create mode 100644 control-plane/src/modules/models/routing.ts create mode 100644 control-plane/src/modules/names.ts create mode 100644 control-plane/src/modules/observability/events.test.ts create mode 100644 control-plane/src/modules/observability/events.ts create mode 100644 control-plane/src/modules/observability/hyperdx.ts create mode 100644 control-plane/src/modules/observability/logger.ts create mode 100644 control-plane/src/modules/observability/rollbar.ts create mode 100644 control-plane/src/modules/observability/tracer.ts create mode 100644 control-plane/src/modules/packer.ts create mode 100644 control-plane/src/modules/posthog.ts create mode 100644 control-plane/src/modules/prompt-templates.test.ts create mode 100644 control-plane/src/modules/prompt-templates.ts create mode 100644 control-plane/src/modules/prompts.test.ts create mode 100644 control-plane/src/modules/prompts.ts create mode 100644 control-plane/src/modules/rate-limiter.test.ts create mode 100644 control-plane/src/modules/rate-limiter.ts create mode 100644 control-plane/src/modules/redis.ts create mode 100644 control-plane/src/modules/result-keys.test.ts create mode 100644 control-plane/src/modules/result-keys.ts create mode 100644 control-plane/src/modules/router.test.ts create mode 100644 control-plane/src/modules/router.ts create mode 100644 control-plane/src/modules/service-definitions.test.ts create mode 100644 control-plane/src/modules/service-definitions.ts create mode 100644 control-plane/src/modules/service-metadata.ts create mode 100644 control-plane/src/modules/sqs.ts create mode 100644 control-plane/src/modules/test/util.ts create mode 100644 control-plane/src/modules/tool-metadata.ts create mode 100644 control-plane/src/modules/util.test.ts create mode 100644 control-plane/src/modules/util.ts create mode 100644 control-plane/src/modules/versioned-entities.ts create mode 100644 control-plane/src/modules/versioned-text.ts create mode 100644 control-plane/src/modules/workflows/agent/agent.ai.test.ts create mode 100644 control-plane/src/modules/workflows/agent/agent.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/edges.test.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/edges.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/model-call.test.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/model-call.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/tool-call.test.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/tool-call.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/tool-parser.test.ts create mode 100644 control-plane/src/modules/workflows/agent/nodes/tool-parser.ts create mode 100644 control-plane/src/modules/workflows/agent/run.test.ts create mode 100644 control-plane/src/modules/workflows/agent/run.ts create mode 100644 control-plane/src/modules/workflows/agent/state.ts create mode 100644 control-plane/src/modules/workflows/agent/summarizer.ts create mode 100644 control-plane/src/modules/workflows/agent/tools/functions.ts create mode 100644 control-plane/src/modules/workflows/agent/tools/knowledge-artifacts.ts create mode 100644 control-plane/src/modules/workflows/agent/tools/mock-function.ts create mode 100644 control-plane/src/modules/workflows/agent/utils.test.ts create mode 100644 control-plane/src/modules/workflows/agent/utils.ts create mode 100644 control-plane/src/modules/workflows/metadata.test.ts create mode 100644 control-plane/src/modules/workflows/metadata.ts create mode 100644 control-plane/src/modules/workflows/notify.ts create mode 100644 control-plane/src/modules/workflows/queues.ts create mode 100644 control-plane/src/modules/workflows/router.ts create mode 100644 control-plane/src/modules/workflows/summarization.ts create mode 100644 control-plane/src/modules/workflows/workflow-messages.ts create mode 100644 control-plane/src/modules/workflows/workflows.test.ts create mode 100644 control-plane/src/modules/workflows/workflows.ts create mode 100644 control-plane/src/utilities/cache.ts create mode 100644 control-plane/src/utilities/constants.ts create mode 100644 control-plane/src/utilities/env.ts create mode 100644 control-plane/src/utilities/errors.ts create mode 100644 control-plane/src/utilities/migrate.ts create mode 100644 control-plane/src/utilities/run-migrate.ts create mode 100644 control-plane/src/utilities/safe-parse.ts create mode 100644 control-plane/tsconfig.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3b9f78ee..7c40a5af 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,6 +24,8 @@ jobs: sdk_go: ${{ steps.filter.outputs.sdk_go }} sdk_react: ${{ steps.filter.outputs.sdk_react }} cli: ${{ steps.filter.outputs.cli }} + control_plane: ${{ steps.filter.outputs.control_plane }} + app: ${{ steps.filter.outputs.app }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -44,6 +46,119 @@ jobs: - 'sdk-react/**' cli: - 'cli/**' + control_plane: + - 'control-plane/**' + app: + - 'app/**' + + build-control-plane: + needs: check_changes + if: ${{ needs.check_changes.outputs.control_plane == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: read + defaults: + run: + working-directory: control-plane + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + cache-dependency-path: control-plane/package-lock.json + - name: Install dependencies + run: npm ci + - name: Build package + run: npm run build + + test-control-plane: + runs-on: ubuntu-latest + needs: [check_changes, build-control-plane] + if: ${{ needs.check_changes.outputs.control_plane == 'true' }} + defaults: + run: + working-directory: control-plane + services: + redis: + image: redis + ports: + - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + postgres: + image: pgvector/pgvector:pg16 + env: + POSTGRES_PASSWORD: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + cache-dependency-path: control-plane/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run tests + run: | + set -eo pipefail + npm run test + if [[ "$(git rev-parse --abbrev-ref HEAD)" == "main" ]]; then + npx run test:ai + fi + env: + REDIS_URL: "redis://localhost:6379" + DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres" + DATABASE_SSL_DISABLED: "1" + JWKS_URL: ${{ secrets.TEST_JWKS_URL }} + AWS_ACCESS_KEY_ID: ${{ secrets.TEST_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.TEST_AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: "ap-southeast-2" + BEDROCK_AVAILABLE: "true" + SQS_RUN_PROCESS_QUEUE_URL: "PLACEHOLDER" + SQS_RUN_GENERATE_NAME_QUEUE_URL: "PLACEHOLDER" + SQS_LEARNING_INGEST_QUEUE_URL: "PLACEHOLDER" + SQS_CUSTOMER_TELEMETRY_QUEUE_URL: "PLACEHOLDER" + SQS_EXTERNAL_TOOL_CALL_QUEUE_URL: "PLACEHOLDER" + + build-app: + needs: check_changes + if: ${{ needs.check_changes.outputs.app == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: read + defaults: + run: + working-directory: app + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "npm" + cache-dependency-path: app/package-lock.json + - name: Install dependencies + run: npm ci + - name: Build package + run: npm run build + env: + NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }} build-node: needs: check_changes diff --git a/app/.dockerignore b/app/.dockerignore new file mode 100644 index 00000000..504d5073 --- /dev/null +++ b/app/.dockerignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/app/.eslintrc.json b/app/.eslintrc.json new file mode 100644 index 00000000..7cd65f50 --- /dev/null +++ b/app/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "extends": [ + "next/core-web-vitals", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/no-unused-vars": 1, + "@typescript-eslint/no-explicit-any": 1 + } +} diff --git a/app/Dockerfile.dev b/app/Dockerfile.dev new file mode 100644 index 00000000..17013777 --- /dev/null +++ b/app/Dockerfile.dev @@ -0,0 +1,16 @@ +FROM node:20 + +WORKDIR /app + +# copy package.json and package-lock.json +COPY --link package.json package-lock.json ./ + +# install dependencies +RUN npm install + +# copy source code +COPY --link . . + +RUN npm install + +ENTRYPOINT [ "npm", "run", "dev" ] \ No newline at end of file diff --git a/app/README.md b/app/README.md new file mode 100644 index 00000000..6af57e22 --- /dev/null +++ b/app/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3001](http://localhost:3001) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/app/app/cli-auth/page.tsx b/app/app/cli-auth/page.tsx new file mode 100644 index 00000000..de92e304 --- /dev/null +++ b/app/app/cli-auth/page.tsx @@ -0,0 +1,67 @@ +"use client"; + +import { useAuth, OrganizationSwitcher } from "@clerk/nextjs"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + CardFooter, +} from "@/components/ui/card"; +import toast from "react-hot-toast"; +import { Loader } from "lucide-react"; + +export default function Page() { + return ( +
+ +
+ ); +} + +function CliAuth() { + const { getToken, orgId, isLoaded } = useAuth(); + + const handleGetToken = async () => { + const newToken = await getToken({ + template: "extended-cli-token", + }); + + if (!newToken) { + toast.error("Failed to get token"); + return; + } + + const url = new URL("http://localhost:9999"); + url.searchParams.append("token", newToken); + window.location.href = url.toString(); + }; + + if (!isLoaded) { + return ; + } + + return ( + + + CLI Authentication + + Select an organization and confirm CLI authentication + + + + + + + + + + ); +} diff --git a/app/app/clusters/[clusterId]/configs/[promptId]/edit/page.tsx b/app/app/clusters/[clusterId]/configs/[promptId]/edit/page.tsx new file mode 100644 index 00000000..40ed8bde --- /dev/null +++ b/app/app/clusters/[clusterId]/configs/[promptId]/edit/page.tsx @@ -0,0 +1,261 @@ +"use client"; + +import { client } from "@/client/client"; +import { contract } from "@/client/contract"; +import { + JobMetricsCharts, + PromptMetricsCharts, +} from "@/components/PromptMetricsCharts"; +import { PromptTemplateForm } from "@/components/chat/prompt-template-form"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { cn, createErrorToast } from "@/lib/utils"; +import { useAuth } from "@clerk/nextjs"; +import { ClientInferResponseBody } from "@ts-rest/core"; +import { ChevronDownIcon } from "lucide-react"; +import { useRouter } from "next/navigation"; +import { useCallback, useEffect, useState } from "react"; +import { toast } from "react-hot-toast"; + +export default function EditPromptTemplate({ + params, +}: { + params: { clusterId: string; promptId: string }; +}) { + const router = useRouter(); + const [isLoading, setIsLoading] = useState(true); + const [promptTemplate, setPromptTemplate] = useState | null>(null); + const { getToken } = useAuth(); + + const [selectedVersion, setSelectedVersion] = useState(null); + + const [metrics, setMetrics] = useState | null>(null); + + const fetchPromptTemplate = useCallback(async () => { + try { + const response = await client.getRunConfig({ + params: { clusterId: params.clusterId, configId: params.promptId }, + query: { + withPreviousVersions: "true", + }, + headers: { + authorization: `Bearer ${await getToken()}`, + }, + }); + + if (response.status === 200) { + setPromptTemplate(response.body); + setSelectedVersion(null); + } else { + createErrorToast(response, "Failed to fetch prompt template"); + } + } catch (error) { + toast.error( + `An error occurred while fetching the prompt template: ${error}`, + ); + } finally { + setIsLoading(false); + } + }, [params.clusterId, params.promptId, getToken]); + + useEffect(() => { + fetchPromptTemplate(); + }, [fetchPromptTemplate]); + + const handleSubmit = async (formData: { + name: string; + initialPrompt?: string; + systemPrompt?: string; + attachedFunctions: string; + public: boolean; + resultSchema?: string; + inputSchema?: string; + }) => { + try { + const response = await client.upsertRunConfig({ + params: { clusterId: params.clusterId, configId: params.promptId }, + body: { + initialPrompt: + formData.initialPrompt === "" ? undefined : formData.initialPrompt, + systemPrompt: + formData.systemPrompt === "" ? undefined : formData.systemPrompt, + name: formData.name === "" ? undefined : formData.name, + public: formData.public, + resultSchema: formData.resultSchema + ? JSON.parse(formData.resultSchema) + : undefined, + inputSchema: formData.inputSchema + ? JSON.parse(formData.inputSchema) + : undefined, + attachedFunctions: formData.attachedFunctions + .split(",") + .map((f) => f.trim()) + .filter((f) => f !== ""), + }, + headers: { + authorization: `Bearer ${await getToken()}`, + }, + }); + + if (response.status === 200) { + toast.success("Run config updated successfully"); + router.push(`/clusters/${params.clusterId}/configs`); + } else { + toast.error(`Failed to update prompt template: ${response.status}`); + } + } catch (error) { + toast.error(`An error occurred while updating the run config: ${error}`); + } + }; + + useEffect(() => { + const fetchMetrics = async () => { + const response = await client.getRunConfigMetrics({ + params: { clusterId: params.clusterId, configId: params.promptId }, + headers: { + authorization: `Bearer ${await getToken()}`, + }, + }); + + if (response.status === 200) { + setMetrics(response.body); + } else { + toast.error(`Failed to fetch metrics: ${response.status}`); + } + }; + + fetchMetrics(); + }, [params.clusterId, params.promptId, getToken]); + + if (isLoading) { + return
Loading...
; + } + + if (!promptTemplate) { + return
Prompt template not found
; + } + + return ( +
+ + + Update Run Configuration + + +

+ Modify your run configuration below. +

+
+ + + + + +
+ + {promptTemplate.versions + .sort((a, b) => b.version - a.version) + .map((version) => ( + + ))} +
+
+
+ +
+ +
+
+ +
+ {metrics ? ( + <> + +
+ + + ) : ( +

Loading metrics...

+ )} +
+
+ ); +} diff --git a/app/app/clusters/[clusterId]/configs/global/page.tsx b/app/app/clusters/[clusterId]/configs/global/page.tsx new file mode 100644 index 00000000..daa018fc --- /dev/null +++ b/app/app/clusters/[clusterId]/configs/global/page.tsx @@ -0,0 +1,195 @@ +"use client"; + +import { client } from "@/client/client"; +import { contract } from "@/client/contract"; +import { Loading } from "@/components/loading"; +import { MarkdownEditor } from "@/components/markdown-editor"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { useAuth } from "@clerk/nextjs"; +import "@mdxeditor/editor/style.css"; +import { ClientInferResponseBody } from "@ts-rest/core"; +import { useCallback, useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import sanitizeHtml from "sanitize-html"; + +// Import necessary plugins +export default function Page({ params }: { params: { clusterId: string } }) { + const { getToken } = useAuth(); + const [clusterContext, setClusterContext] = useState< + | ClientInferResponseBody< + typeof contract.getCluster, + 200 + >["additionalContext"] + | null + >(null); + const [error, setError] = useState(null); + const [isSaving, setIsSaving] = useState(false); + const [activePrompt, setActivePrompt] = useState(""); + const [wordCount, setWordCount] = useState(0); + const [fetched, setFetched] = useState(false); + + const fetchClusterContext = useCallback(async () => { + const response = await client.getCluster({ + params: { clusterId: params.clusterId }, + headers: { authorization: `Bearer ${await getToken()}` }, + }); + + if (response.status === 200) { + setClusterContext(response.body.additionalContext); + const sanitizedContent = sanitizeHtml( + response.body.additionalContext?.current.content ?? "" + ); + setActivePrompt(sanitizedContent); + setFetched(true); + } else { + throw new Error(`Failed to fetch cluster context: ${response.status}`); + } + + setError(null); + }, [params.clusterId, getToken]); + + useEffect(() => { + fetchClusterContext(); + }, [fetchClusterContext]); + + useEffect(() => { + const words = activePrompt.trim().split(/\s+/).length; + setWordCount(words); + }, [activePrompt]); + + const handleSave = async () => { + const markdown = activePrompt; + const currentVersionHasChanged = + clusterContext?.current.content !== markdown; + + if (!currentVersionHasChanged) { + toast.error("No changes to save"); + return; + } + + const currentVersion = Number( + clusterContext?.history + .map((version) => version.version) + .reduce( + (latest, version) => (version > latest ? version : latest), + clusterContext.current.version, + ) ?? 0, + ); + + const history = clusterContext + ? [ + ...clusterContext.history, + { + version: clusterContext.current.version, + content: clusterContext.current.content, + }, + ] + .sort((a, b) => Number(b.version) - Number(a.version)) + .slice(0, 5) + : []; + + setIsSaving(true); + + try { + const token = await getToken(); + if (!token) throw new Error("No token available"); + + const response = await client.updateCluster({ + params: { clusterId: params.clusterId }, + headers: { authorization: token }, + body: { + additionalContext: { + current: { + version: String(currentVersion + 1), + content: markdown, + }, + history, + }, + }, + }); + + if (response.status !== 204) { + throw new Error("Failed to update cluster context"); + } + + fetchClusterContext(); + + toast.success("Cluster context updated successfully"); + } catch (err) { + console.error(err); + toast.error("Failed to update cluster context"); + } finally { + setIsSaving(false); + } + }; + + if (error) { + return
Error: {error}
; + } + + if (!fetched) { + return ; + } + + return ( +
+ + + Edit Global Context + + Update your global context. This will be included in all runs. + + + + {clusterContext && ( +
+

Previous Versions

+
+ {clusterContext.history.map((version, index) => ( + + ))} +
+
+ )} +

+ Current Version (v{clusterContext?.current.version}) +

+ { + setActivePrompt(markdown); + }} + /> +
+
+ {wordCount} {wordCount === 1 ? "word" : "words"} + {wordCount > 300 && ( + + Warning: Exceeds 300 words + + )} +
+
+ +
+
+
+ ); +} diff --git a/app/app/clusters/[clusterId]/configs/layout.tsx b/app/app/clusters/[clusterId]/configs/layout.tsx new file mode 100644 index 00000000..3ef4abdf --- /dev/null +++ b/app/app/clusters/[clusterId]/configs/layout.tsx @@ -0,0 +1,3 @@ +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
; +} diff --git a/app/app/clusters/[clusterId]/configs/new/page.tsx b/app/app/clusters/[clusterId]/configs/new/page.tsx new file mode 100644 index 00000000..0a86f5ab --- /dev/null +++ b/app/app/clusters/[clusterId]/configs/new/page.tsx @@ -0,0 +1,105 @@ +"use client"; + +import { client } from "@/client/client"; +import { PromptTemplateForm } from "@/components/chat/prompt-template-form"; +import { createErrorToast } from "@/lib/utils"; +import { useAuth } from "@clerk/nextjs"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { toast } from "react-hot-toast"; + +export default function NewPromptTemplate({ + params, +}: { + params: { clusterId: string }; +}) { + const router = useRouter(); + const [isLoading, setIsLoading] = useState(false); + const { getToken } = useAuth(); + const handleSubmit = async (formData: { + name: string; + initialPrompt?: string; + systemPrompt?: string; + public: boolean; + attachedFunctions: string; + resultSchema?: string; + inputSchema?: string; + }) => { + setIsLoading(true); + if (formData.name === "") { + toast.error("Please enter a name for the Run Configuration"); + return; + } + + try { + const response = await client.createRunConfig({ + params: { clusterId: params.clusterId }, + body: { + name: formData.name, + initialPrompt: + formData.initialPrompt === "" ? undefined : formData.initialPrompt, + systemPrompt: + formData.systemPrompt === "" ? undefined : formData.systemPrompt, + public: formData.public, + resultSchema: formData.resultSchema + ? JSON.parse(formData.resultSchema) + : undefined, + inputSchema: formData.inputSchema + ? JSON.parse(formData.inputSchema) + : undefined, + attachedFunctions: formData.attachedFunctions + .split(",") + .map((f) => f.trim()) + .filter((f) => f !== ""), + }, + headers: { + authorization: `Bearer ${await getToken()}`, + }, + }); + + if (response.status === 201) { + toast.success("Run Configuration created successfully"); + router.push( + `/clusters/${params.clusterId}/configs/${response.body.id}/edit`, + ); + } else { + createErrorToast(response, "Failed to create Run Configuration"); + } + } catch (error) { + toast.error( + `An error occurred while creating the Run Configuration: ${error}`, + ); + } finally { + setIsLoading(false); + } + }; + + return ( +
+

Create New Run Configuration

+

+
+ Please see our{" "} + + docs + {" "} + for more information +

+ +
+ ); +} diff --git a/app/app/clusters/[clusterId]/configs/page.tsx b/app/app/clusters/[clusterId]/configs/page.tsx new file mode 100644 index 00000000..34785fca --- /dev/null +++ b/app/app/clusters/[clusterId]/configs/page.tsx @@ -0,0 +1,220 @@ +"use client"; + +import { client } from "@/client/client"; +import { contract } from "@/client/contract"; +import { Button } from "@/components/ui/button"; +import { DataTable } from "@/components/ui/data-table"; +import { useAuth } from "@clerk/nextjs"; +import { ColumnDef } from "@tanstack/react-table"; +import { ClientInferResponseBody } from "@ts-rest/core"; +import { formatDistanceToNow } from "date-fns"; +import { ArrowUpDown, Globe, PlusIcon } from "lucide-react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +type Prompt = ClientInferResponseBody< + typeof contract.listRunConfigs, + 200 +>[number]; + +const columns: ColumnDef[] = [ + { + accessorKey: "name", + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => ( +
+

{row.getValue("name")}

+

+ {row.original.initialPrompt} +

+ {row.original.attachedFunctions.filter(Boolean).length > 0 && ( +
+ {row.original.attachedFunctions.map((tool) => ( + + {tool} + + ))} +
+ )} +
+ ), + }, + { + id: "id", + header: "Configuration ID", + cell: ({ row }) => ( +
{row.original.id}
+ ), + }, + { + id: "lastUpdated", + header: "Last Updated", + cell: ({ row }) => ( +

+ {row.original.updatedAt + ? formatDistanceToNow(new Date(row.original.updatedAt), { + addSuffix: true, + }) + : "N/A"} +

+ ), + }, + { + id: "actions", + cell: function Cell({ row }) { + const [isDeleting, setIsDeleting] = useState(false); + const { getToken } = useAuth(); + const router = useRouter(); + + const handleDelete = async () => { + if ( + confirm("Are you sure you want to delete this Run Configuration?") + ) { + setIsDeleting(true); + try { + const token = await getToken(); + if (!token) throw new Error("No token available"); + + const response = await client.deleteRunConfig({ + params: { + clusterId: row.original.clusterId, + configId: row.original.id, + }, + headers: { authorization: token }, + }); + + if (response.status !== 204) { + throw new Error("Failed to delete Run Configuration"); + } else { + router.refresh(); + } + } catch (err) { + console.error(err); + alert("An error occurred while deleting the Run Configuration"); + } finally { + setIsDeleting(false); + } + } + }; + + return ( +
+ + + +
+ ); + }, + }, +]; + +export default function Page({ params }: { params: { clusterId: string } }) { + const { getToken } = useAuth(); + const [prompts, setPrompts] = useState< + ClientInferResponseBody + >([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const router = useRouter(); + + useEffect(() => { + const fetchPrompts = async () => { + setIsLoading(true); + try { + const token = await getToken(); + + const response = await client.listRunConfigs({ + params: { clusterId: params.clusterId }, + headers: { authorization: `Bearer ${token}` }, + }); + + if (response.status !== 200) { + throw new Error("Failed to fetch run configs"); + } + + setPrompts(response.body); + setError(null); + } catch (err) { + setError("An error occurred while fetching run configs"); + console.error(err); + } finally { + setIsLoading(false); + } + }; + + fetchPrompts(); + }, [params.clusterId, getToken]); + + if (isLoading) { + return
Loading run configurations...
; + } + + if (error) { + return
Error: {error}
; + } + + return ( +
+

Saved Run Configurations

+

+ Saved run configurations are reusable configurations that can be used in + your next run. +

+
+ + +
+ +
+ ); +} diff --git a/app/app/clusters/[clusterId]/integrations/langfuse/page.tsx b/app/app/clusters/[clusterId]/integrations/langfuse/page.tsx new file mode 100644 index 00000000..00eb494b --- /dev/null +++ b/app/app/clusters/[clusterId]/integrations/langfuse/page.tsx @@ -0,0 +1,232 @@ +"use client"; + +import { client } from "@/client/client"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { createErrorToast } from "@/lib/utils"; +import { useAuth } from "@clerk/nextjs"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useCallback, useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import toast from "react-hot-toast"; +import { z } from "zod"; +import { ArrowLeft } from "lucide-react"; +import Link from "next/link"; +import { Switch } from "@/components/ui/switch"; +import { Loading } from "@/components/loading"; + +const formSchema = z.object({ + secretKey: z.string().min(1, "API key is required"), + publicKey: z.string().min(1, "Public key is required"), + baseUrl: z.string().min(1, "Base URL is required"), + sendMessagePayloads: z + .boolean() + .describe( + "Send all message payloads or just the LLM metadata? (LLM metadata includes the LLM response, tokens, and latency)", + ) + .default(false), +}); + +export default function LangfuseIntegration({ + params: { clusterId }, +}: { + params: { clusterId: string }; +}) { + const { getToken } = useAuth(); + const [loading, setLoading] = useState(false); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + secretKey: "", + publicKey: "", + baseUrl: "", + sendMessagePayloads: false, + }, + }); + + const onSubmit = async (data: z.infer) => { + const response = await client.upsertIntegrations({ + headers: { + authorization: `Bearer ${await getToken()}`, + }, + params: { + clusterId: clusterId, + }, + body: { + langfuse: { + secretKey: data.secretKey, + publicKey: data.publicKey, + baseUrl: data.baseUrl, + sendMessagePayloads: data.sendMessagePayloads, + }, + }, + }); + + if (response.status === 200) { + toast.success("Integration updated"); + await fetchConfig(); + return; + } else { + createErrorToast(response, "Failed to update integration"); + } + }; + + const fetchConfig = useCallback(async () => { + setLoading(true); + const response = await client.getIntegrations({ + headers: { + authorization: `Bearer ${await getToken()}`, + }, + params: { + clusterId: clusterId, + }, + }); + setLoading(false); + + if (response.status === 200) { + const result = z + .object({ + secretKey: z.string(), + publicKey: z.string(), + baseUrl: z.string(), + sendMessagePayloads: z.boolean(), + }) + .safeParse(response.body?.langfuse); + + if (result.success) { + form.setValue("secretKey", result.data.secretKey); + form.setValue("publicKey", result.data.publicKey); + form.setValue("baseUrl", result.data.baseUrl); + form.setValue("sendMessagePayloads", result.data.sendMessagePayloads); + } + } + }, [clusterId, getToken, form]); + + useEffect(() => { + fetchConfig(); + }, [fetchConfig]); + + if (loading) { + return ; + } + + return ( +
+
+ + + Back to integrations + +
+ + + +
+ 📊 + Configure Langfuse +
+ + Connect your Langfuse account to send LLM telemetry data for + monitoring and analytics. You can find your API keys in your + Langfuse dashboard. + +
+ +
+ + ( + + Secret API Key + + + + + Your Langfuse secret API key + + + + )} + /> + ( + + Public Key + + + + Your Langfuse public key + + + )} + /> + ( + + Base URL + + + + + Langfuse API base URL. For US region, use{" "} + https://us.cloud.langfuse.com + + + + )} + /> + ( + + Send Message Payloads + + + + + {field.value + ? "Inferable will send all metadata and payloads for every LLM call" + : "Inferable will only send LLM metadata like token count and latency"} + + + + )} + /> + + + +
+
+
+ ); +} diff --git a/app/app/clusters/[clusterId]/integrations/layout.tsx b/app/app/clusters/[clusterId]/integrations/layout.tsx new file mode 100644 index 00000000..a12db3c1 --- /dev/null +++ b/app/app/clusters/[clusterId]/integrations/layout.tsx @@ -0,0 +1,3 @@ +export default function Layout({ children }: { children: React.ReactNode }) { + return
{children}
; +} diff --git a/app/app/clusters/[clusterId]/integrations/page.tsx b/app/app/clusters/[clusterId]/integrations/page.tsx new file mode 100644 index 00000000..98c68b41 --- /dev/null +++ b/app/app/clusters/[clusterId]/integrations/page.tsx @@ -0,0 +1,145 @@ +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, +} from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import Link from "next/link"; +import { ArrowRight, Trash2 } from "lucide-react"; +import { client } from "@/client/client"; +import { auth } from "@clerk/nextjs"; +import ErrorDisplay from "@/components/error-display"; +import { revalidatePath } from "next/cache"; + +const config = { + toolhouse: { + name: "Toolhouse", + description: + "Connect your toolhouse.ai tools directly to your Inferable Runs", + icon: "🛠️", + slug: "toolhouse", + }, + langfuse: { + name: "Langfuse", + description: "Send LLM telemetry to Langfuse for monitoring and analytics", + icon: "📊", + slug: "langfuse", + }, +}; + +export default async function IntegrationsPage({ + params: { clusterId }, +}: { + params: { clusterId: string }; +}) { + const { getToken } = auth(); + + const response = await client.getIntegrations({ + headers: { + authorization: `Bearer ${await getToken()}`, + }, + params: { + clusterId, + }, + }); + + if (response.status !== 200) { + return ; + } + + async function handleUninstall(formData: FormData) { + "use server"; + + const name = formData.get("name") as string; + + const { getToken } = auth(); + + await client.upsertIntegrations({ + headers: { + authorization: `Bearer ${await getToken()}`, + }, + params: { clusterId }, + body: { + [name]: null, + }, + }); + + revalidatePath(`/clusters/${clusterId}/integrations`); + } + + return ( +
+
+

Integrations

+

+ Connect your Inferable cluster with other tools and services +

+ +
+ {Object.entries(response.body).map(([key, integration]) => ( + + +
+ {key} +
+ + {config[key as keyof typeof config]?.description ?? "Unknown"} + +
+ +
+ + + + {integration !== null && ( +
+ + +
+ )} +
+
+
+ ))} + + + +
+ Zapier +
+ + Integrate your Inferable Runs with Zapier + +
+ + + + + +
+
+
+
+ ); +} diff --git a/app/app/clusters/[clusterId]/integrations/toolhouse/page.tsx b/app/app/clusters/[clusterId]/integrations/toolhouse/page.tsx new file mode 100644 index 00000000..293a7b9c --- /dev/null +++ b/app/app/clusters/[clusterId]/integrations/toolhouse/page.tsx @@ -0,0 +1,165 @@ +"use client"; + +import { client } from "@/client/client"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { createErrorToast } from "@/lib/utils"; +import { useAuth } from "@clerk/nextjs"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useCallback, useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import toast from "react-hot-toast"; +import { z } from "zod"; +import { ArrowLeft } from "lucide-react"; +import Link from "next/link"; +import { Loading } from "@/components/loading"; + +const formSchema = z.object({ + apiKey: z.string().min(1, "API key is required"), +}); + +export default function ToolhouseIntegration({ + params: { clusterId }, +}: { + params: { clusterId: string }; +}) { + const { getToken } = useAuth(); + const [loading, setLoading] = useState(false); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + apiKey: "", + }, + }); + + const onSubmit = async (data: z.infer) => { + const response = await client.upsertIntegrations({ + headers: { + authorization: `Bearer ${await getToken()}`, + }, + params: { + clusterId: clusterId, + }, + body: { + toolhouse: { + apiKey: data.apiKey, + }, + }, + }); + + if (response.status === 200) { + toast.success("Integration updated"); + await fetchConfig(); + return; + } else { + console.error(response); + createErrorToast(response, "Failed to update integration"); + } + }; + + const fetchConfig = useCallback(async () => { + setLoading(true); + const response = await client.getIntegrations({ + headers: { + authorization: `Bearer ${await getToken()}`, + }, + params: { + clusterId: clusterId, + }, + }); + setLoading(false); + + if (response.status === 200) { + const result = z + .object({ + apiKey: z.string(), + }) + .safeParse(response.body?.toolhouse); + + if (result.success) { + form.setValue("apiKey", result.data.apiKey); + } + } + }, [clusterId, getToken, form]); + + useEffect(() => { + fetchConfig(); + }, [fetchConfig]); + + if (loading) { + return ; + } + + return ( +
+
+ + + Back to integrations + +
+ + + +
+ 🛠️ + Configure Toolhouse +
+ + Connect your Toolhouse account to use your installed tools in this + cluster. For more information, see{" "} + + our docs + + . + +
+ +
+ + ( + + API Key + + + + Your Toolhouse API key + + + )} + /> + + + +
+
+
+ ); +} diff --git a/app/app/clusters/[clusterId]/knowledge/[artifactId]/edit/page.tsx b/app/app/clusters/[clusterId]/knowledge/[artifactId]/edit/page.tsx new file mode 100644 index 00000000..5258d486 --- /dev/null +++ b/app/app/clusters/[clusterId]/knowledge/[artifactId]/edit/page.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useAuth } from "@clerk/nextjs"; +import { client } from "@/client/client"; +import toast from "react-hot-toast"; +import { useParams, useRouter } from "next/navigation"; +import { + KnowledgeArtifactForm, + KnowledgeArtifact, +} from "@/components/KnowledgeArtifactForm"; +import { createErrorToast } from "@/lib/utils"; + +export default function EditKnowledgeArtifact() { + const { getToken } = useAuth(); + const params = useParams(); + const router = useRouter(); + const clusterId = params?.clusterId as string; + const artifactId = params?.artifactId as string; + const [artifact, setArtifact] = useState(null); + + useEffect(() => { + const fetchArtifact = async () => { + try { + const token = await getToken(); + const response = await client.getKnowledgeArtifact({ + params: { clusterId, artifactId }, + headers: { authorization: token as string }, + }); + + if (response.status === 200) { + setArtifact(response.body); + } else { + createErrorToast(response, "Artifact not found"); + router.push(`/clusters/${clusterId}/knowledge`); + } + } catch (error) { + console.error("Error fetching artifact:", error); + toast.error("Failed to fetch knowledge artifact"); + } + }; + + fetchArtifact(); + }, [getToken, clusterId, artifactId, router]); + + const handleUpdate = async (updatedArtifact: KnowledgeArtifact) => { + try { + const token = await getToken(); + + const response = await client.upsertKnowledgeArtifact({ + params: { clusterId, artifactId }, + headers: { authorization: token as string }, + body: updatedArtifact, + }); + + if (response.status === 200) { + toast.success("Knowledge artifact updated successfully"); + } else { + createErrorToast(response, "Failed to update knowledge artifact"); + } + } catch (error) { + console.error("Error updating artifact:", error); + toast.error("Failed to update knowledge artifact"); + } + }; + + if (!artifact) { + return null; + } + + return ( + router.push(`/clusters/${clusterId}/knowledge`)} + submitButtonText="Update Artifact" + editing={true} + /> + ); +} diff --git a/app/app/clusters/[clusterId]/knowledge/layout.tsx b/app/app/clusters/[clusterId]/knowledge/layout.tsx new file mode 100644 index 00000000..80ef9167 --- /dev/null +++ b/app/app/clusters/[clusterId]/knowledge/layout.tsx @@ -0,0 +1,270 @@ +"use client"; + +import { client } from "@/client/client"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Textarea } from "@/components/ui/textarea"; +import { useAuth } from "@clerk/nextjs"; +import { truncate } from "lodash"; +import { GlobeIcon, PlusIcon, TrashIcon, UploadIcon } from "lucide-react"; +import Link from "next/link"; +import { useParams, useRouter } from "next/navigation"; +import { useCallback, useEffect, useState } from "react"; +import toast from "react-hot-toast"; + +type KnowledgeArtifact = { + id: string; + data: string; + tags: string[]; + title: string; + similarity?: number; +}; + +export default function KnowledgeLayout({ + children, +}: { + children: React.ReactNode; +}) { + const { getToken } = useAuth(); + const params = useParams(); + const router = useRouter(); + const clusterId = params?.clusterId as string; + const [artifacts, setArtifacts] = useState([]); + const [searchQuery, setSearchQuery] = useState(""); + const [isUploadDialogOpen, setIsUploadDialogOpen] = useState(false); + const [bulkUploadJson, setBulkUploadJson] = useState(""); + + const fetchArtifacts = useCallback(async () => { + try { + const token = await getToken(); + const response = await client.getKnowledge({ + params: { clusterId }, + headers: { authorization: token as string }, + query: { query: searchQuery, limit: 20 }, + }); + + if (response.status === 200) { + setArtifacts(response.body); + } + } catch (error) { + console.error("Error fetching artifacts:", error); + toast.error("Failed to fetch knowledge artifacts"); + } + }, [getToken, clusterId, searchQuery]); + + useEffect(() => { + fetchArtifacts(); + }, [fetchArtifacts]); + + const handleSearch = () => { + fetchArtifacts(); + }; + + const handleDelete = async (id: string) => { + try { + const token = await getToken(); + const response = await client.deleteKnowledgeArtifact({ + params: { clusterId, artifactId: id }, + headers: { authorization: token as string }, + }); + + if (response.status === 204) { + toast.success("Knowledge artifact deleted successfully"); + fetchArtifacts(); + } + } catch (error) { + console.error("Error deleting artifact:", error); + toast.error("Failed to delete knowledge artifact"); + } + }; + + const handleBulkUpload = async () => { + try { + const artifacts = JSON.parse(bulkUploadJson); + if (!Array.isArray(artifacts)) { + throw new Error("Invalid JSON format. Expected an array of artifacts."); + } + + const loading = toast.loading("Uploading knowledge artifacts..."); + + const token = await getToken(); + let successCount = 0; + let failCount = 0; + + for (const artifact of artifacts) { + try { + const response = await client.upsertKnowledgeArtifact({ + params: { clusterId, artifactId: artifact.id }, + headers: { authorization: token as string }, + body: artifact, + }); + + if (response.status === 201) { + successCount++; + } else { + failCount++; + } + } catch (error) { + console.error("Error creating artifact:", error); + failCount++; + } + } + + toast.remove(loading); + toast.success( + `Bulk upload completed. Success: ${successCount}, Failed: ${failCount}`, + ); + setIsUploadDialogOpen(false); + fetchArtifacts(); + } catch (error) { + console.error("Error parsing JSON:", error); + toast.error( + "Failed to parse JSON. Please check the format and try again.", + ); + } + }; + + return ( +
+
+
+
+ + + +
+ + + + + + + + Bulk Upload Knowledge Artifacts + +
+

+ Paste your JSON array of knowledge artifacts below. Note + that items with the same ID will be overwritten. +

+