Skip to content

Commit a7115e8

Browse files
authored
feat(integrations): add Azure Data Explorer (#6701)
* feat(integrations): add Azure Data Explorer Add a 14-operation Azure Data Explorer (Kusto) integration covering KQL queries, schema and metadata discovery, table management, inline and query-sourced ingestion, ingestion-failure triage, and arbitrary management commands. Authentication uses a Microsoft Entra service principal through an internal proxy route, since the Kusto token audience is per-cluster and cannot be expressed as a static-scope OAuth provider. * fix(azure-data-explorer): only read partial-failure status from the QueryStatus table Scanning every returned table for Severity and StatusDescription columns misread an ordinary query as a failed request whenever the user's own result selected columns of those names — a common shape for a log table. Failure detection now consults only the table the response's table of contents names as QueryStatus, and primary-result selection reuses the same index instead of re-reading it. * fix(azure-data-explorer): keep the Show Operations and Show Table Details cards from painting empty check:canvas-sentences flagged the Show Operations sentence: it anchored `core` on operationId, which is an advanced-mode optional field, so an untouched card resolved to nothing and painted empty. Show Table Details had the same shape in milder form — table is optional there, since omitting it describes every table, leaving a dangling preposition. Both now lead with literal copy and treat their field as an optional refinement. Also simplifies the primary-table condition to a single `!= null` check. * fix(azure-data-explorer): authenticate sovereign clusters against their own Entra authority The cluster allowlist accepted Azure China and US Government hosts, but every token request went to login.microsoftonline.com. Those clouds are isolated instances with their own Entra endpoints, so a sovereign cluster passed URI validation and then could never obtain a token. Each Kusto service domain is now declared alongside the authority that issues tokens for it, so the two cannot drift apart, and the authority is part of the token cache key. * improvement(azure-data-explorer): warn that ingest-from-query matches columns by position Kusto aligns an ingested query result to the target table on column type and order, never on column name, so a query projecting the right columns in the wrong order lands data in the wrong columns without erroring. Surfaces that in the tool description and param the model reads, in the wand prompt that generates the query, in the rollup skill's steps, and in the docs. Also verifies the target schema first rather than after. * chore(azure-data-explorer): drop the unsourced kustomfa host from the cluster allowlist Every other entry traces to a Microsoft reference — the Kusto connection-string doc, the national-cloud endpoint tables, and the Fabric KQL-database REST reference. kustomfa.windows.net does not, and the connection-string doc states the trust boundary as hostnames ending in kusto.windows.net. An allowlist should only hold hosts we can justify, so this drops it and records the sourcing standard for anything added later. * fix(azure-data-explorer): handle commas inside quoted properties and empty extent IDs Two defects in the shared command helpers: buildWithClause split the property list on every comma before validating, so a value that legally contains one — a docstring sentence, or a tags array with more than one entry — was torn in half and rejected. Splitting is now quote-aware, and an unterminated quote is rejected outright rather than swallowing the rest of the clause. transformColumnListResponse dropped empty strings, but `.ingest inline` reports "no data shards were generated" as a single record carrying an empty extent ID. A no-op load therefore looked like a missing column instead of an empty result. Only non-strings are skipped now.
1 parent 1d34272 commit a7115e8

36 files changed

Lines changed: 4790 additions & 5 deletions

apps/docs/components/icons.tsx

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3898,6 +3898,138 @@ export const ClaudeIcon = (props: SVGProps<SVGSVGElement>) => (
38983898
</svg>
38993899
)
39003900

3901+
export function AzureDataExplorerIcon(props: SVGProps<SVGSVGElement>) {
3902+
const id = useId()
3903+
const wedgeGradient = `adx_wedge_${id}`
3904+
const dashLongGradient = `adx_dash_long_${id}`
3905+
const dashTopGradient = `adx_dash_top_${id}`
3906+
const dashBottomGradient = `adx_dash_bottom_${id}`
3907+
3908+
return (
3909+
<svg
3910+
{...props}
3911+
width='18'
3912+
height='18'
3913+
viewBox='0 0 18 18'
3914+
fill='none'
3915+
xmlns='http://www.w3.org/2000/svg'
3916+
>
3917+
<path
3918+
d='M1.47,1.47,16.53,16.53a.57.57,0,0,0,1-.4V1.07A.57.57,0,0,0,16.93.5H1.87A.57.57,0,0,0,1.47,1.47Z'
3919+
fill={`url(#${wedgeGradient})`}
3920+
/>
3921+
<path d='M5.53,5.53l6.94,6.94,5-5V1.07A.57.57,0,0,0,16.93.5H10.56Z' fill='#50e6ff' />
3922+
<rect
3923+
x='-0.38'
3924+
y='12.85'
3925+
width='9.37'
3926+
height='1.7'
3927+
rx='0.27'
3928+
transform='translate(-8.43 7.06) rotate(-45)'
3929+
fill={`url(#${dashLongGradient})`}
3930+
/>
3931+
<rect
3932+
x='0.12'
3933+
y='9.23'
3934+
width='5.99'
3935+
height='1.7'
3936+
rx='0.27'
3937+
transform='translate(-6.22 5.15) rotate(-45)'
3938+
fill={`url(#${dashTopGradient})`}
3939+
/>
3940+
<rect
3941+
x='4.89'
3942+
y='14.04'
3943+
width='5.99'
3944+
height='1.7'
3945+
rx='0.27'
3946+
transform='translate(-8.22 9.93) rotate(-45)'
3947+
fill={`url(#${dashBottomGradient})`}
3948+
/>
3949+
<rect
3950+
x='9.19'
3951+
y='4.75'
3952+
width='1.7'
3953+
height='1.7'
3954+
rx='0.38'
3955+
transform='translate(-1.02 8.74) rotate(-45)'
3956+
fill='#fff'
3957+
/>
3958+
<rect
3959+
x='11.59'
3960+
y='2.35'
3961+
width='1.7'
3962+
height='1.7'
3963+
rx='0.38'
3964+
transform='translate(1.38 9.73) rotate(-45)'
3965+
fill='#fff'
3966+
/>
3967+
<rect
3968+
x='11.59'
3969+
y='7.15'
3970+
width='1.7'
3971+
height='1.7'
3972+
rx='0.38'
3973+
transform='translate(-2.01 11.14) rotate(-45)'
3974+
fill='#fff'
3975+
/>
3976+
<path
3977+
d='M13.91,5.33l.66-.66a.38.38,0,0,1,.54,0l.66.66a.38.38,0,0,1,0,.54l-.66.66a.38.38,0,0,1-.54,0l-.66-.66a.38.38,0,0,1,0-.54'
3978+
fill='#fff'
3979+
/>
3980+
<defs>
3981+
<linearGradient
3982+
id={wedgeGradient}
3983+
x1='1.3'
3984+
y1='8.6'
3985+
x2='17.5'
3986+
y2='8.6'
3987+
gradientUnits='userSpaceOnUse'
3988+
>
3989+
<stop offset='0.1' stopColor='#54aef0' />
3990+
<stop offset='1' stopColor='#1988d9' />
3991+
</linearGradient>
3992+
<linearGradient
3993+
id={dashLongGradient}
3994+
x1='0.5'
3995+
y1='13.7'
3996+
x2='8.11'
3997+
y2='13.7'
3998+
gradientTransform='translate(10.95 0.97) rotate(45)'
3999+
gradientUnits='userSpaceOnUse'
4000+
>
4001+
<stop offset='0' stopColor='#b3b2b3' />
4002+
<stop offset='1' stopColor='#979797' />
4003+
</linearGradient>
4004+
<linearGradient
4005+
id={dashTopGradient}
4006+
x1='0.5'
4007+
y1='10.08'
4008+
x2='5.72'
4009+
y2='10.08'
4010+
gradientTransform='translate(8.04 0.75) rotate(45)'
4011+
gradientUnits='userSpaceOnUse'
4012+
>
4013+
<stop offset='0' stopColor='#b3b2b3' />
4014+
<stop offset='1' stopColor='#979797' />
4015+
</linearGradient>
4016+
<linearGradient
4017+
id={dashBottomGradient}
4018+
x1='5.28'
4019+
y1='14.89'
4020+
x2='10.49'
4021+
y2='14.89'
4022+
gradientTransform='translate(12.84 -1.21) rotate(45)'
4023+
gradientUnits='userSpaceOnUse'
4024+
>
4025+
<stop offset='0' stopColor='#b3b2b3' />
4026+
<stop offset='1' stopColor='#979797' />
4027+
</linearGradient>
4028+
</defs>
4029+
</svg>
4030+
)
4031+
}
4032+
39014033
export function AzureIcon(props: SVGProps<SVGSVGElement>) {
39024034
const id = useId()
39034035
const gradient0 = `azure_paint0_${id}`

apps/docs/components/ui/icon-mapping.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
AshbyIcon,
2323
AthenaIcon,
2424
AttioIcon,
25+
AzureDataExplorerIcon,
2526
AzureIcon,
2627
BoxCompanyIcon,
2728
BrainIcon,
@@ -281,6 +282,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
281282
ashby: AshbyIcon,
282283
athena: AthenaIcon,
283284
attio: AttioIcon,
285+
azure_data_explorer: AzureDataExplorerIcon,
284286
azure_devops: AzureIcon,
285287
box: BoxCompanyIcon,
286288
brandfetch: BrandfetchIcon,

0 commit comments

Comments
 (0)