feat(dagster): expand integration with 9 new tools and full GraphQL validation (#4013)

* feat(blocks): add dagster block

* type safety improvements

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* unify error handeling across dg tool

* update icon to daggy

* update icon to daggy

* feat(dagster): expand integration with 9 new tools and full GraphQL validation

- Add 9 new tools: delete_run, get_run_logs, reexecute_run, list_schedules,
  start_schedule, stop_schedule, list_sensors, start_sensor, stop_sensor
- Fix GraphQL union type handling across all tools (replace invalid `... on Error`
  with concrete union member fragments per Dagster schema)
- Fix TerminateRunFailure, InvalidStepError, InvalidOutputError handling in existing tools
- Rename graphql.ts → utils.ts for clarity
- Wire all 14 operations into the Dagster block with proper conditions and param remapping
- Update icon to dagster logo SVG and set bgColor to white
- Add block wiring guidance to the add-tools skill

* fix(dagster): replace invalid `... on Error` interface spreads with concrete union members

- list_runs: InvalidPipelineRunsFilterError + PythonError
- list_jobs: RepositoryNotFoundError + PythonError
- reexecute_run: PipelineNotFoundError, RunConflict, UnauthorizedError, PythonError
- terminate_run: RunNotFoundError, UnauthorizedError, PythonError
- delete_run: RunNotFoundError, UnauthorizedError, PythonError
- list_sensors: RepositoryNotFoundError + PythonError
- start_sensor: SensorNotFoundError, UnauthorizedError, PythonError
- stop_sensor: UnauthorizedError + PythonError
- stop_schedule: fix $id variable type String! → String (matches nullable schema arg)
- dagster.mdx: add manual intro description section

* docs

* fix(dagster): add RunConfigValidationInvalid handling to launch_run and use concrete error types

* fix(dagster): replace ... on Error with concrete RunNotFoundError + PythonError in get_run and get_run_logs

* fix(dagster): add missing LaunchRunResult union members (InvalidSubsetError, PresetNotFoundError, ConflictingExecutionParamsError, NoModeProvidedError)

* fix(dagster): always override jobName in list_runs params to prevent stale launch_run value leaking

---------

Co-authored-by: abhinavDhulipala <abhinav.dhulipala@berkeley.edu>
Co-authored-by: abhinavDhulipala <46908860+abhinavDhulipala@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
Waleed
2026-04-07 11:33:21 -07:00
committed by GitHub
parent 5c7b057599
commit 24af61dcbb
28 changed files with 3345 additions and 3 deletions

View File

@@ -4929,6 +4929,49 @@ export function SSHIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function DagsterIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='21 21 518 518' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
d='M221.556 440.815C221.562 442.771 221.97 444.704 222.757 446.494C223.543 448.285 224.689 449.894 226.125 451.221C227.56 452.548 229.254 453.565 231.1 454.208C232.946 454.851 234.905 455.107 236.854 454.959C310.941 449.655 380.913 397.224 403.252 315.332C404.426 310.622 407.96 308.26 412.669 308.26C415.082 308.357 417.36 309.402 419.009 311.168C420.658 312.933 421.545 315.278 421.477 317.694C421.477 335.953 398.006 383.674 364.442 411.368C362.731 412.807 361.367 414.614 360.452 416.654C359.536 418.694 359.092 420.914 359.154 423.149C359.188 424.967 359.58 426.76 360.308 428.425C361.036 430.091 362.086 431.596 363.397 432.855C364.708 434.114 366.254 435.101 367.948 435.761C369.641 436.421 371.448 436.739 373.264 436.699C376.205 436.699 380.913 434.931 386.795 429.627C410.266 408.412 455 348.909 455 283.508C455 187.624 380.872 105 277.418 105C185.106 105 105.138 180.414 105.138 267.611C105.138 325.345 151.004 368.937 211.56 368.937C258.019 368.937 300.945 335.953 312.708 290.58C313.881 285.87 317.402 283.508 322.11 283.508C324.525 283.606 326.804 284.65 328.455 286.415C330.106 288.181 330.996 290.525 330.933 292.942C330.933 313.564 292.122 385.484 213.327 385.484C194.509 385.484 170.996 380.18 154.524 370.746C152.319 369.677 149.917 369.075 147.469 368.978C145.594 368.906 143.725 369.223 141.979 369.909C140.232 370.594 138.647 371.634 137.321 372.962C135.996 374.291 134.96 375.879 134.278 377.627C133.596 379.376 133.283 381.247 133.359 383.122C133.435 385.524 134.123 387.867 135.357 389.929C136.592 391.991 138.332 393.703 140.414 394.904C162.173 407.334 188.047 413.757 214.501 413.757C280.359 413.757 340.335 368.978 357.98 302.997C359.154 298.287 362.688 295.926 367.383 295.926C369.797 296.023 372.077 297.067 373.728 298.832C375.379 300.598 376.269 302.943 376.205 305.359C376.205 332.459 327.992 419.655 235.087 426.727C231.492 426.994 228.123 428.579 225.625 431.18C223.128 433.78 221.679 437.211 221.556 440.815V440.815Z'
fill='#4F43DD'
/>
<path
d='M313.62 215.178C326.301 215.083 338.748 218.589 349.517 225.288C350.605 219.33 351.206 213.292 351.312 207.236C351.312 179.266 329.995 154.211 304.038 154.211C283.853 154.211 271.233 170.937 271.233 191.6C271.137 202.763 275.057 213.588 282.279 222.098C292.062 217.431 302.782 215.064 313.62 215.178V215.178Z'
fill='white'
/>
<path
d='M374.439 316.505C378.042 304.185 379.63 295.635 379.63 290.083C379.52 287.685 378.493 285.421 376.761 283.76C375.028 282.099 372.724 281.168 370.325 281.16C368.089 281.202 365.932 281.99 364.196 283.399C362.46 284.808 361.244 286.757 360.743 288.936C359.762 292.983 357.664 303.95 355.593 310.912C356.449 308.306 357.231 305.658 357.94 302.97C359.114 298.246 362.648 295.898 367.342 295.898C369.756 295.991 372.035 297.033 373.687 298.796C375.338 300.559 376.228 302.902 376.165 305.318C376.054 309.115 375.446 312.881 374.356 316.519L374.439 316.505Z'
fill='#352D8E'
/>
<path
d='M424.418 303.632C424.305 301.237 423.278 298.977 421.55 297.317C419.821 295.658 417.522 294.724 415.126 294.709C412.893 294.754 410.739 295.543 409.006 296.952C407.272 298.36 406.059 300.308 405.558 302.485C404.564 306.629 402.424 317.761 400.325 324.709H400.422C401.444 321.615 402.396 318.48 403.183 315.289C404.357 310.565 407.891 308.217 412.599 308.217C415.012 308.311 417.29 309.353 418.939 311.116C420.588 312.88 421.475 315.223 421.408 317.637C421.341 320.569 420.938 323.485 420.207 326.325C423.134 316.049 424.418 308.618 424.418 303.632Z'
fill='#352D8E'
/>
<path
d='M313.619 215.178C319.921 215.166 326.196 216.007 332.272 217.678C335.462 213.326 337.056 208.008 336.786 202.618C336.516 197.228 334.398 192.095 330.789 188.084C327.18 184.073 322.3 181.428 316.97 180.594C311.64 179.761 306.185 180.789 301.524 183.507L311.189 199.419L293.089 191.587C290.637 195.545 289.407 200.139 289.555 204.793C289.702 209.446 291.22 213.953 293.917 217.747C300.34 216.016 306.967 215.152 313.619 215.178V215.178Z'
fill='#030615'
/>
<path
d='M174.172 317.583C181.797 317.583 187.979 311.399 187.979 303.771C187.979 296.143 181.797 289.959 174.172 289.959C166.547 289.959 160.365 296.143 160.365 303.771C160.365 311.399 166.547 317.583 174.172 317.583Z'
fill='#352D8E'
/>
<path
d='M174.172 262.335C181.797 262.335 187.979 256.151 187.979 248.523C187.979 240.895 181.797 234.711 174.172 234.711C166.547 234.711 160.365 240.895 160.365 248.523C160.365 256.151 166.547 262.335 174.172 262.335Z'
fill='#352D8E'
/>
<path
d='M146.558 289.958C154.183 289.958 160.364 283.774 160.364 276.146C160.364 268.518 154.183 262.334 146.558 262.334C138.932 262.334 132.751 268.518 132.751 276.146C132.751 283.774 138.932 289.958 146.558 289.958Z'
fill='#352D8E'
/>
<path
d='M208.688 368.91H211.45C257.909 368.91 300.835 335.927 312.598 290.554C313.771 285.844 317.292 283.482 322 283.482C324.415 283.579 326.694 284.624 328.345 286.389C329.996 288.155 330.886 290.499 330.823 292.916C330.612 297.737 329.522 302.479 327.606 306.908C327.939 306.393 328.23 305.853 328.476 305.292C331.969 297.304 333.774 288.679 333.777 279.96C333.777 266.41 324.361 257.571 310.844 257.571C287.276 257.571 282.554 278.151 272.614 300.154C262.3 322.999 243.357 347.709 195.586 347.709C145.951 347.709 94.9487 312.944 107.389 242.253C107.54 241.369 107.665 240.582 107.761 239.85C105.939 248.982 105.014 258.272 105 267.584C105.138 324.491 149.582 367.585 208.688 368.91Z'
fill='#352D8E'
/>
</svg>
)
}
export function DatabricksIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 241 266' fill='none' xmlns='http://www.w3.org/2000/svg'>

View File

@@ -32,6 +32,7 @@ import {
CloudWatchIcon,
ConfluenceIcon,
CursorIcon,
DagsterIcon,
DatabricksIcon,
DatadogIcon,
DevinIcon,
@@ -218,6 +219,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
cloudwatch: CloudWatchIcon,
confluence_v2: ConfluenceIcon,
cursor_v2: CursorIcon,
dagster: DagsterIcon,
databricks: DatabricksIcon,
datadog: DatadogIcon,
devin: DevinIcon,

View File

@@ -0,0 +1,343 @@
---
title: Dagster
description: Orchestrate data pipelines and manage job runs with Dagster
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="dagster"
color="#ffffff"
/>
{/* MANUAL-CONTENT-START:intro */}
[Dagster](https://dagster.io/) is an open-source data orchestration platform designed for building, testing, and monitoring data pipelines. It provides a unified model for defining data assets, scheduling jobs, and observing pipeline execution — whether running locally or deployed to Dagster+.
With Dagster, you can:
- **Orchestrate data pipelines**: Define and run jobs composed of ops and assets with full dependency tracking
- **Monitor executions**: Track run status, inspect logs, and debug failures step by step
- **Manage schedules and sensors**: Automate pipeline triggers on a cron schedule or in response to external events
- **Reexecute selectively**: Resume failed pipelines from the point of failure without rerunning successful steps
In Sim, the Dagster integration enables your agents to interact with a Dagster instance programmatically. Agents can launch and monitor job runs, retrieve execution logs, reexecute failed runs, and manage schedules and sensors — all as part of a larger automated workflow. Use Dagster as an orchestration layer your agents can control and observe, enabling data-driven automation that responds dynamically to pipeline outcomes.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Connect to a Dagster instance to launch job runs, monitor run status, list available jobs across repositories, terminate or delete runs, reexecute failed runs, fetch run logs, and manage schedules and sensors. API token only required for Dagster+.
## Tools
### `dagster_launch_run`
Launch a job run on a Dagster instance.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3000\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `repositoryLocationName` | string | Yes | Repository location \(code location\) name |
| `repositoryName` | string | Yes | Repository name within the code location |
| `jobName` | string | Yes | Name of the job to launch |
| `runConfigJson` | string | No | Run configuration as a JSON object \(optional\) |
| `tags` | string | No | Tags as a JSON array of \{key, value\} objects \(optional\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `runId` | string | The globally unique ID of the launched run |
### `dagster_get_run`
Get the status and details of a Dagster run by its ID.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3000\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `runId` | string | Yes | The ID of the run to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `runId` | string | Run ID |
| `jobName` | string | Name of the job this run belongs to |
| `status` | string | Run status \(QUEUED, NOT_STARTED, STARTING, MANAGED, STARTED, SUCCESS, FAILURE, CANCELING, CANCELED\) |
| `startTime` | number | Run start time as Unix timestamp |
| `endTime` | number | Run end time as Unix timestamp |
| `runConfigYaml` | string | Run configuration as YAML |
| `tags` | json | Run tags as array of \{key, value\} objects |
### `dagster_get_run_logs`
Fetch execution event logs for a Dagster run.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `runId` | string | Yes | The ID of the run to fetch logs for |
| `afterCursor` | string | No | Cursor for paginating through log events \(from a previous response\) |
| `limit` | number | No | Maximum number of log events to return |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `events` | json | Array of log events \(type, message, timestamp, level, stepKey, eventType\) |
| ↳ `type` | string | GraphQL typename of the event |
| ↳ `message` | string | Human-readable log message |
| ↳ `timestamp` | string | Event timestamp as a Unix epoch string |
| ↳ `level` | string | Log level \(DEBUG, INFO, WARNING, ERROR, CRITICAL\) |
| ↳ `stepKey` | string | Step key, if the event is step-scoped |
| ↳ `eventType` | string | Dagster event type enum value |
| `cursor` | string | Cursor for fetching the next page of log events |
| `hasMore` | boolean | Whether more log events are available beyond this page |
### `dagster_list_runs`
List recent Dagster runs, optionally filtered by job name.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `jobName` | string | No | Filter runs by job name \(optional\) |
| `statuses` | string | No | Comma-separated run statuses to filter by, e.g. "SUCCESS,FAILURE" \(optional\) |
| `limit` | number | No | Maximum number of runs to return \(default 20\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `runs` | json | Array of runs |
| ↳ `runId` | string | Run ID |
| ↳ `jobName` | string | Job name |
| ↳ `status` | string | Run status |
| ↳ `tags` | json | Run tags as array of \{key, value\} objects |
| ↳ `startTime` | number | Start time as Unix timestamp |
| ↳ `endTime` | number | End time as Unix timestamp |
### `dagster_list_jobs`
List all jobs across repositories in a Dagster instance.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `jobs` | json | Array of jobs with name and repositoryName |
| ↳ `name` | string | Job name |
| ↳ `repositoryName` | string | Repository name |
### `dagster_reexecute_run`
Reexecute an existing Dagster run, optionally resuming only from failed steps.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `parentRunId` | string | Yes | The ID of the run to reexecute |
| `strategy` | string | Yes | Reexecution strategy: ALL_STEPS reruns everything, FROM_FAILURE resumes from failed steps, FROM_ASSET_FAILURE resumes from failed assets |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `runId` | string | The ID of the newly launched reexecution run |
### `dagster_terminate_run`
Terminate an in-progress Dagster run.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `runId` | string | Yes | The ID of the run to terminate |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the run was successfully terminated |
| `runId` | string | The ID of the terminated run |
| `message` | string | Error or status message if termination failed |
### `dagster_delete_run`
Permanently delete a Dagster run record.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `runId` | string | Yes | The ID of the run to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `runId` | string | The ID of the deleted run |
### `dagster_list_schedules`
List all schedules in a Dagster repository, optionally filtered by status.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `repositoryLocationName` | string | Yes | Repository location \(code location\) name |
| `repositoryName` | string | Yes | Repository name within the code location |
| `scheduleStatus` | string | No | Filter schedules by status: RUNNING or STOPPED \(omit to return all\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `schedules` | json | Array of schedules \(name, cronSchedule, jobName, status, id, description, executionTimezone\) |
| ↳ `name` | string | Schedule name |
| ↳ `cronSchedule` | string | Cron expression for the schedule |
| ↳ `jobName` | string | Job the schedule targets |
| ↳ `status` | string | Schedule status: RUNNING or STOPPED |
| ↳ `id` | string | Instigator state ID — use this to start or stop the schedule |
| ↳ `description` | string | Human-readable schedule description |
| ↳ `executionTimezone` | string | Timezone for cron evaluation |
### `dagster_start_schedule`
Enable (start) a schedule in a Dagster repository.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `repositoryLocationName` | string | Yes | Repository location \(code location\) name |
| `repositoryName` | string | Yes | Repository name within the code location |
| `scheduleName` | string | Yes | Name of the schedule to start |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Instigator state ID of the schedule |
| `status` | string | Updated schedule status \(RUNNING or STOPPED\) |
### `dagster_stop_schedule`
Disable (stop) a running schedule in Dagster.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `instigationStateId` | string | Yes | InstigationState ID of the schedule to stop — available from dagster_list_schedules output |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Instigator state ID of the schedule |
| `status` | string | Updated schedule status \(RUNNING or STOPPED\) |
### `dagster_list_sensors`
List all sensors in a Dagster repository, optionally filtered by status.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `repositoryLocationName` | string | Yes | Repository location \(code location\) name |
| `repositoryName` | string | Yes | Repository name within the code location |
| `sensorStatus` | string | No | Filter sensors by status: RUNNING or STOPPED \(omit to return all\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sensors` | json | Array of sensors \(name, sensorType, status, id, description\) |
| ↳ `name` | string | Sensor name |
| ↳ `sensorType` | string | Sensor type \(ASSET, AUTO_MATERIALIZE, FRESHNESS_POLICY, MULTI_ASSET, RUN_STATUS, STANDARD\) |
| ↳ `status` | string | Sensor status: RUNNING or STOPPED |
| ↳ `id` | string | Instigator state ID — use this to start or stop the sensor |
| ↳ `description` | string | Human-readable sensor description |
### `dagster_start_sensor`
Enable (start) a sensor in a Dagster repository.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `repositoryLocationName` | string | Yes | Repository location \(code location\) name |
| `repositoryName` | string | Yes | Repository name within the code location |
| `sensorName` | string | Yes | Name of the sensor to start |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Instigator state ID of the sensor |
| `status` | string | Updated sensor status \(RUNNING or STOPPED\) |
### `dagster_stop_sensor`
Disable (stop) a running sensor in Dagster.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `host` | string | Yes | Dagster host URL \(e.g., https://myorg.dagster.cloud/prod or http://localhost:3001\) |
| `apiKey` | string | No | Dagster+ API token \(leave blank for OSS / self-hosted\) |
| `instigationStateId` | string | Yes | InstigationState ID of the sensor to stop — available from dagster_list_sensors output |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Instigator state ID of the sensor |
| `status` | string | Updated sensor status \(RUNNING or STOPPED\) |

View File

@@ -27,6 +27,7 @@
"cloudwatch",
"confluence",
"cursor",
"dagster",
"databricks",
"datadog",
"devin",

View File

@@ -32,6 +32,7 @@ import {
CloudWatchIcon,
ConfluenceIcon,
CursorIcon,
DagsterIcon,
DatabricksIcon,
DatadogIcon,
DevinIcon,
@@ -218,6 +219,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
cloudwatch: CloudWatchIcon,
confluence_v2: ConfluenceIcon,
cursor_v2: CursorIcon,
dagster: DagsterIcon,
databricks: DatabricksIcon,
datadog: DatadogIcon,
devin: DevinIcon,

View File

@@ -2345,6 +2345,81 @@
"integrationType": "developer-tools",
"tags": ["agentic", "automation"]
},
{
"type": "dagster",
"slug": "dagster",
"name": "Dagster",
"description": "Orchestrate data pipelines and manage job runs with Dagster",
"longDescription": "Connect to a Dagster instance to launch job runs, monitor run status, list available jobs across repositories, terminate or delete runs, reexecute failed runs, fetch run logs, and manage schedules and sensors. API token only required for Dagster+.",
"bgColor": "#ffffff",
"iconName": "DagsterIcon",
"docsUrl": "https://docs.sim.ai/tools/dagster",
"operations": [
{
"name": "Launch Run",
"description": "Launch a job run on a Dagster instance."
},
{
"name": "Get Run",
"description": "Get the status and details of a Dagster run by its ID."
},
{
"name": "Get Run Logs",
"description": "Fetch execution event logs for a Dagster run."
},
{
"name": "List Runs",
"description": "List recent Dagster runs, optionally filtered by job name."
},
{
"name": "List Jobs",
"description": "List all jobs across repositories in a Dagster instance."
},
{
"name": "Reexecute Run",
"description": "Reexecute an existing Dagster run, optionally resuming only from failed steps."
},
{
"name": "Terminate Run",
"description": "Terminate an in-progress Dagster run."
},
{
"name": "Delete Run",
"description": "Permanently delete a Dagster run record."
},
{
"name": "List Schedules",
"description": "List all schedules in a Dagster repository, optionally filtered by status."
},
{
"name": "Start Schedule",
"description": "Enable (start) a schedule in a Dagster repository."
},
{
"name": "Stop Schedule",
"description": "Disable (stop) a running schedule in Dagster."
},
{
"name": "List Sensors",
"description": "List all sensors in a Dagster repository, optionally filtered by status."
},
{
"name": "Start Sensor",
"description": "Enable (start) a sensor in a Dagster repository."
},
{
"name": "Stop Sensor",
"description": "Disable (stop) a running sensor in Dagster."
}
],
"operationCount": 14,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",
"category": "tools",
"integrationType": "automation",
"tags": ["data-analytics", "automation"]
},
{
"type": "databricks",
"slug": "databricks",

View File

@@ -0,0 +1,423 @@
import { DagsterIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { IntegrationType } from '@/blocks/types'
import type { DagsterResponse } from '@/tools/dagster/types'
export const DagsterBlock: BlockConfig<DagsterResponse> = {
type: 'dagster',
name: 'Dagster',
description: 'Orchestrate data pipelines and manage job runs with Dagster',
longDescription:
'Connect to a Dagster instance to launch job runs, monitor run status, list available jobs across repositories, terminate or delete runs, reexecute failed runs, fetch run logs, and manage schedules and sensors. API token only required for Dagster+.',
docsLink: 'https://docs.sim.ai/tools/dagster',
category: 'tools',
integrationType: IntegrationType.Automation,
tags: ['data-analytics', 'automation'],
bgColor: '#ffffff',
icon: DagsterIcon,
subBlocks: [
// ── Operation selector ─────────────────────────────────────────────────────
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
options: [
{ label: 'Launch Run', id: 'launch_run' },
{ label: 'Get Run', id: 'get_run' },
{ label: 'Get Run Logs', id: 'get_run_logs' },
{ label: 'List Runs', id: 'list_runs' },
{ label: 'List Jobs', id: 'list_jobs' },
{ label: 'Reexecute Run', id: 'reexecute_run' },
{ label: 'Terminate Run', id: 'terminate_run' },
{ label: 'Delete Run', id: 'delete_run' },
{ label: 'List Schedules', id: 'list_schedules' },
{ label: 'Start Schedule', id: 'start_schedule' },
{ label: 'Stop Schedule', id: 'stop_schedule' },
{ label: 'List Sensors', id: 'list_sensors' },
{ label: 'Start Sensor', id: 'start_sensor' },
{ label: 'Stop Sensor', id: 'stop_sensor' },
],
value: () => 'launch_run',
},
// ── Repository selectors (launch_run + schedule/sensor operations) ─────────
{
id: 'repositoryLocationName',
title: 'Repository Location',
type: 'short-input',
placeholder: 'e.g., my_code_location',
condition: {
field: 'operation',
value: ['launch_run', 'list_schedules', 'start_schedule', 'list_sensors', 'start_sensor'],
},
required: {
field: 'operation',
value: ['launch_run', 'list_schedules', 'start_schedule', 'list_sensors', 'start_sensor'],
},
},
{
id: 'repositoryName',
title: 'Repository Name',
type: 'short-input',
placeholder: 'e.g., __repository__',
condition: {
field: 'operation',
value: ['launch_run', 'list_schedules', 'start_schedule', 'list_sensors', 'start_sensor'],
},
required: {
field: 'operation',
value: ['launch_run', 'list_schedules', 'start_schedule', 'list_sensors', 'start_sensor'],
},
},
// ── Launch Run ─────────────────────────────────────────────────────────────
{
id: 'jobName',
title: 'Job Name',
type: 'short-input',
placeholder: 'e.g., my_pipeline_job',
condition: { field: 'operation', value: 'launch_run' },
required: { field: 'operation', value: 'launch_run' },
},
{
id: 'runConfigJson',
title: 'Run Config',
type: 'code',
placeholder: '{"ops": {"my_op": {"config": {"key": "value"}}}}',
condition: { field: 'operation', value: 'launch_run' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: `Generate a Dagster run config JSON object based on the user's description.
Examples:
- "set partition date to 2024-01-15" -> {"ops": {"load_partition": {"config": {"partition_date": "2024-01-15"}}}}
- "run with debug logging" -> {"execution": {"multiprocess": {"config": {"max_concurrent": 1}}}}
Return ONLY a valid JSON object - no explanations, no extra text.`,
placeholder: 'Describe the run configuration...',
generationType: 'json-object',
},
},
{
id: 'tags',
title: 'Tags',
type: 'code',
placeholder: '[{"key": "env", "value": "prod"}]',
condition: { field: 'operation', value: 'launch_run' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: `Generate a Dagster execution tags JSON array based on the user's description.
Format: [{"key": "string", "value": "string"}, ...]
Examples:
- "tag env as prod" -> [{"key": "env", "value": "prod"}]
- "mark as nightly run owned by data team" -> [{"key": "schedule", "value": "nightly"}, {"key": "owner", "value": "data-team"}]
Return ONLY a valid JSON array - no explanations, no extra text.`,
placeholder: 'Describe the tags to attach to this run...',
generationType: 'json-object',
},
},
// ── Run ID (shared: get_run, get_run_logs, terminate_run, delete_run, reexecute_run) ──
{
id: 'runId',
title: 'Run ID',
type: 'short-input',
placeholder: 'e.g., abc123def456',
condition: {
field: 'operation',
value: ['get_run', 'get_run_logs', 'terminate_run', 'delete_run', 'reexecute_run'],
},
required: {
field: 'operation',
value: ['get_run', 'get_run_logs', 'terminate_run', 'delete_run', 'reexecute_run'],
},
},
// ── Reexecute Run ──────────────────────────────────────────────────────────
{
id: 'strategy',
title: 'Reexecution Strategy',
type: 'dropdown',
options: [
{ label: 'All Steps', id: 'ALL_STEPS' },
{ label: 'From Failure', id: 'FROM_FAILURE' },
{ label: 'From Asset Failure', id: 'FROM_ASSET_FAILURE' },
],
value: () => 'ALL_STEPS',
condition: { field: 'operation', value: 'reexecute_run' },
required: { field: 'operation', value: 'reexecute_run' },
},
// ── Get Run Logs ───────────────────────────────────────────────────────────
{
id: 'afterCursor',
title: 'After Cursor',
type: 'short-input',
placeholder: 'Cursor from a previous get_run_logs response (for pagination)',
condition: { field: 'operation', value: 'get_run_logs' },
mode: 'advanced',
},
{
id: 'logsLimit',
title: 'Limit',
type: 'short-input',
placeholder: '100',
condition: { field: 'operation', value: 'get_run_logs' },
mode: 'advanced',
},
// ── List Runs ──────────────────────────────────────────────────────────────
{
id: 'listRunsJobName',
title: 'Job Name Filter',
type: 'short-input',
placeholder: 'Filter by job name (optional)',
condition: { field: 'operation', value: 'list_runs' },
},
{
id: 'statuses',
title: 'Status Filter',
type: 'short-input',
placeholder: 'e.g. SUCCESS,FAILURE (optional)',
condition: { field: 'operation', value: 'list_runs' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: `Generate a comma-separated list of Dagster run statuses to filter by.
Valid statuses: QUEUED, NOT_STARTED, STARTING, MANAGED, STARTED, SUCCESS, FAILURE, CANCELING, CANCELED
Examples:
- "only failed runs" -> FAILURE
- "completed runs (success or failure)" -> SUCCESS,FAILURE
- "runs in progress" -> QUEUED,NOT_STARTED,STARTING,STARTED
Return ONLY the comma-separated status values - no explanations, no extra text.`,
placeholder: 'Describe which run statuses to include...',
},
},
{
id: 'limit',
title: 'Limit',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'list_runs' },
mode: 'advanced',
},
// ── Schedule operations ────────────────────────────────────────────────────
{
id: 'scheduleName',
title: 'Schedule Name',
type: 'short-input',
placeholder: 'e.g., my_daily_schedule',
condition: { field: 'operation', value: 'start_schedule' },
required: { field: 'operation', value: 'start_schedule' },
},
{
id: 'scheduleStatus',
title: 'Status Filter',
type: 'dropdown',
options: [
{ label: 'All', id: '' },
{ label: 'Running', id: 'RUNNING' },
{ label: 'Stopped', id: 'STOPPED' },
],
value: () => '',
condition: { field: 'operation', value: 'list_schedules' },
mode: 'advanced',
},
// ── Sensor operations ──────────────────────────────────────────────────────
{
id: 'sensorName',
title: 'Sensor Name',
type: 'short-input',
placeholder: 'e.g., my_asset_sensor',
condition: { field: 'operation', value: 'start_sensor' },
required: { field: 'operation', value: 'start_sensor' },
},
{
id: 'sensorStatus',
title: 'Status Filter',
type: 'dropdown',
options: [
{ label: 'All', id: '' },
{ label: 'Running', id: 'RUNNING' },
{ label: 'Stopped', id: 'STOPPED' },
],
value: () => '',
condition: { field: 'operation', value: 'list_sensors' },
mode: 'advanced',
},
// ── Stop schedule / sensor (shared) ────────────────────────────────────────
{
id: 'instigationStateId',
title: 'Instigator State ID',
type: 'short-input',
placeholder: 'ID from list_schedules or list_sensors output',
condition: { field: 'operation', value: ['stop_schedule', 'stop_sensor'] },
required: { field: 'operation', value: ['stop_schedule', 'stop_sensor'] },
},
// ── Connection (common to all operations) ──────────────────────────────────
{
id: 'host',
title: 'Host',
type: 'short-input',
placeholder: 'http://localhost:3001 or https://myorg.dagster.cloud/prod',
required: true,
},
{
id: 'apiKey',
title: 'API Token',
type: 'short-input',
placeholder: 'Dagster+ API token (leave blank for OSS / self-hosted)',
password: true,
},
],
tools: {
access: [
'dagster_launch_run',
'dagster_get_run',
'dagster_get_run_logs',
'dagster_list_runs',
'dagster_list_jobs',
'dagster_reexecute_run',
'dagster_terminate_run',
'dagster_delete_run',
'dagster_list_schedules',
'dagster_start_schedule',
'dagster_stop_schedule',
'dagster_list_sensors',
'dagster_start_sensor',
'dagster_stop_sensor',
],
config: {
tool: (params) => `dagster_${params.operation}`,
params: (params) => {
const result: Record<string, unknown> = {}
// list_runs: type-coerce limit and remap job name filter
if (params.operation === 'list_runs') {
if (params.limit != null && params.limit !== '') result.limit = Number(params.limit)
result.jobName = params.listRunsJobName || undefined
}
// get_run_logs: remap logsLimit → limit
if (params.operation === 'get_run_logs') {
if (params.logsLimit != null && params.logsLimit !== '')
result.limit = Number(params.logsLimit)
}
// reexecute_run: remap runId → parentRunId
if (params.operation === 'reexecute_run') {
if (params.runId) result.parentRunId = params.runId
}
// list_schedules / list_sensors: drop empty status filter
if (params.operation === 'list_schedules' && !params.scheduleStatus) {
result.scheduleStatus = undefined
}
if (params.operation === 'list_sensors' && !params.sensorStatus) {
result.sensorStatus = undefined
}
return result
},
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
host: { type: 'string', description: 'Dagster host URL' },
apiKey: {
type: 'string',
description: 'Dagster Cloud API token (optional for self-hosted instances)',
},
// Launch Run
repositoryLocationName: { type: 'string', description: 'Repository location name' },
repositoryName: { type: 'string', description: 'Repository name' },
jobName: { type: 'string', description: 'Job name to launch' },
runConfigJson: { type: 'string', description: 'Run configuration as JSON' },
tags: { type: 'string', description: 'Tags as JSON array of {key, value} objects' },
// Run ID operations
runId: { type: 'string', description: 'Run ID' },
// Reexecute Run
strategy: {
type: 'string',
description: 'Reexecution strategy (ALL_STEPS, FROM_FAILURE, FROM_ASSET_FAILURE)',
},
// Get Run Logs
afterCursor: { type: 'string', description: 'Pagination cursor for run logs' },
logsLimit: { type: 'number', description: 'Maximum log events to return' },
// List Runs
listRunsJobName: { type: 'string', description: 'Filter list_runs by job name' },
statuses: { type: 'string', description: 'Comma-separated run statuses to filter by' },
limit: { type: 'number', description: 'Maximum results to return' },
// Schedules
scheduleName: { type: 'string', description: 'Schedule name' },
scheduleStatus: {
type: 'string',
description: 'Filter schedules by status (RUNNING or STOPPED)',
},
// Sensors
sensorName: { type: 'string', description: 'Sensor name' },
sensorStatus: { type: 'string', description: 'Filter sensors by status (RUNNING or STOPPED)' },
// Stop schedule / sensor
instigationStateId: { type: 'string', description: 'InstigationState ID for stop operations' },
},
outputs: {
// Launch Run / Reexecute Run / Delete Run / Get Run
runId: { type: 'string', description: 'Run ID' },
// Get Run
jobName: { type: 'string', description: 'Job name the run belongs to' },
status: { type: 'string', description: 'Run or schedule/sensor status' },
startTime: { type: 'number', description: 'Run start time (Unix timestamp)' },
endTime: { type: 'number', description: 'Run end time (Unix timestamp)' },
runConfigYaml: { type: 'string', description: 'Run configuration as YAML' },
tags: { type: 'json', description: 'Run tags as array of {key, value} objects' },
// List Runs
runs: {
type: 'json',
description: 'List of runs (runId, jobName, status, tags, startTime, endTime)',
},
// List Jobs
jobs: { type: 'json', description: 'List of jobs (name, repositoryName)' },
// Terminate Run
success: { type: 'boolean', description: 'Whether termination succeeded' },
message: { type: 'string', description: 'Termination status or error message' },
// Get Run Logs
events: {
type: 'json',
description: 'Log events (type, message, timestamp, level, stepKey, eventType)',
},
cursor: { type: 'string', description: 'Pagination cursor for the next page of logs' },
hasMore: {
type: 'boolean',
description: 'Whether more log events are available beyond this page',
},
// List Schedules
schedules: {
type: 'json',
description:
'List of schedules (name, cronSchedule, jobName, status, id, description, executionTimezone)',
},
// List Sensors
sensors: {
type: 'json',
description: 'List of sensors (name, sensorType, status, id, description)',
},
// Start/Stop schedule or sensor
id: { type: 'string', description: 'Instigator state ID of the schedule or sensor' },
},
}

View File

@@ -30,6 +30,7 @@ import { ConditionBlock } from '@/blocks/blocks/condition'
import { ConfluenceBlock, ConfluenceV2Block } from '@/blocks/blocks/confluence'
import { CredentialBlock } from '@/blocks/blocks/credential'
import { CursorBlock, CursorV2Block } from '@/blocks/blocks/cursor'
import { DagsterBlock } from '@/blocks/blocks/dagster'
import { DatabricksBlock } from '@/blocks/blocks/databricks'
import { DatadogBlock } from '@/blocks/blocks/datadog'
import { DevinBlock } from '@/blocks/blocks/devin'
@@ -254,6 +255,7 @@ export const registry: Record<string, BlockConfig> = {
confluence_v2: ConfluenceV2Block,
cursor: CursorBlock,
cursor_v2: CursorV2Block,
dagster: DagsterBlock,
databricks: DatabricksBlock,
datadog: DatadogBlock,
devin: DevinBlock,

View File

@@ -4929,6 +4929,49 @@ export function SSHIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function DagsterIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='21 21 518 518' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
d='M221.556 440.815C221.562 442.771 221.97 444.704 222.757 446.494C223.543 448.285 224.689 449.894 226.125 451.221C227.56 452.548 229.254 453.565 231.1 454.208C232.946 454.851 234.905 455.107 236.854 454.959C310.941 449.655 380.913 397.224 403.252 315.332C404.426 310.622 407.96 308.26 412.669 308.26C415.082 308.357 417.36 309.402 419.009 311.168C420.658 312.933 421.545 315.278 421.477 317.694C421.477 335.953 398.006 383.674 364.442 411.368C362.731 412.807 361.367 414.614 360.452 416.654C359.536 418.694 359.092 420.914 359.154 423.149C359.188 424.967 359.58 426.76 360.308 428.425C361.036 430.091 362.086 431.596 363.397 432.855C364.708 434.114 366.254 435.101 367.948 435.761C369.641 436.421 371.448 436.739 373.264 436.699C376.205 436.699 380.913 434.931 386.795 429.627C410.266 408.412 455 348.909 455 283.508C455 187.624 380.872 105 277.418 105C185.106 105 105.138 180.414 105.138 267.611C105.138 325.345 151.004 368.937 211.56 368.937C258.019 368.937 300.945 335.953 312.708 290.58C313.881 285.87 317.402 283.508 322.11 283.508C324.525 283.606 326.804 284.65 328.455 286.415C330.106 288.181 330.996 290.525 330.933 292.942C330.933 313.564 292.122 385.484 213.327 385.484C194.509 385.484 170.996 380.18 154.524 370.746C152.319 369.677 149.917 369.075 147.469 368.978C145.594 368.906 143.725 369.223 141.979 369.909C140.232 370.594 138.647 371.634 137.321 372.962C135.996 374.291 134.96 375.879 134.278 377.627C133.596 379.376 133.283 381.247 133.359 383.122C133.435 385.524 134.123 387.867 135.357 389.929C136.592 391.991 138.332 393.703 140.414 394.904C162.173 407.334 188.047 413.757 214.501 413.757C280.359 413.757 340.335 368.978 357.98 302.997C359.154 298.287 362.688 295.926 367.383 295.926C369.797 296.023 372.077 297.067 373.728 298.832C375.379 300.598 376.269 302.943 376.205 305.359C376.205 332.459 327.992 419.655 235.087 426.727C231.492 426.994 228.123 428.579 225.625 431.18C223.128 433.78 221.679 437.211 221.556 440.815V440.815Z'
fill='#4F43DD'
/>
<path
d='M313.62 215.178C326.301 215.083 338.748 218.589 349.517 225.288C350.605 219.33 351.206 213.292 351.312 207.236C351.312 179.266 329.995 154.211 304.038 154.211C283.853 154.211 271.233 170.937 271.233 191.6C271.137 202.763 275.057 213.588 282.279 222.098C292.062 217.431 302.782 215.064 313.62 215.178V215.178Z'
fill='white'
/>
<path
d='M374.439 316.505C378.042 304.185 379.63 295.635 379.63 290.083C379.52 287.685 378.493 285.421 376.761 283.76C375.028 282.099 372.724 281.168 370.325 281.16C368.089 281.202 365.932 281.99 364.196 283.399C362.46 284.808 361.244 286.757 360.743 288.936C359.762 292.983 357.664 303.95 355.593 310.912C356.449 308.306 357.231 305.658 357.94 302.97C359.114 298.246 362.648 295.898 367.342 295.898C369.756 295.991 372.035 297.033 373.687 298.796C375.338 300.559 376.228 302.902 376.165 305.318C376.054 309.115 375.446 312.881 374.356 316.519L374.439 316.505Z'
fill='#352D8E'
/>
<path
d='M424.418 303.632C424.305 301.237 423.278 298.977 421.55 297.317C419.821 295.658 417.522 294.724 415.126 294.709C412.893 294.754 410.739 295.543 409.006 296.952C407.272 298.36 406.059 300.308 405.558 302.485C404.564 306.629 402.424 317.761 400.325 324.709H400.422C401.444 321.615 402.396 318.48 403.183 315.289C404.357 310.565 407.891 308.217 412.599 308.217C415.012 308.311 417.29 309.353 418.939 311.116C420.588 312.88 421.475 315.223 421.408 317.637C421.341 320.569 420.938 323.485 420.207 326.325C423.134 316.049 424.418 308.618 424.418 303.632Z'
fill='#352D8E'
/>
<path
d='M313.619 215.178C319.921 215.166 326.196 216.007 332.272 217.678C335.462 213.326 337.056 208.008 336.786 202.618C336.516 197.228 334.398 192.095 330.789 188.084C327.18 184.073 322.3 181.428 316.97 180.594C311.64 179.761 306.185 180.789 301.524 183.507L311.189 199.419L293.089 191.587C290.637 195.545 289.407 200.139 289.555 204.793C289.702 209.446 291.22 213.953 293.917 217.747C300.34 216.016 306.967 215.152 313.619 215.178V215.178Z'
fill='#030615'
/>
<path
d='M174.172 317.583C181.797 317.583 187.979 311.399 187.979 303.771C187.979 296.143 181.797 289.959 174.172 289.959C166.547 289.959 160.365 296.143 160.365 303.771C160.365 311.399 166.547 317.583 174.172 317.583Z'
fill='#352D8E'
/>
<path
d='M174.172 262.335C181.797 262.335 187.979 256.151 187.979 248.523C187.979 240.895 181.797 234.711 174.172 234.711C166.547 234.711 160.365 240.895 160.365 248.523C160.365 256.151 166.547 262.335 174.172 262.335Z'
fill='#352D8E'
/>
<path
d='M146.558 289.958C154.183 289.958 160.364 283.774 160.364 276.146C160.364 268.518 154.183 262.334 146.558 262.334C138.932 262.334 132.751 268.518 132.751 276.146C132.751 283.774 138.932 289.958 146.558 289.958Z'
fill='#352D8E'
/>
<path
d='M208.688 368.91H211.45C257.909 368.91 300.835 335.927 312.598 290.554C313.771 285.844 317.292 283.482 322 283.482C324.415 283.579 326.694 284.624 328.345 286.389C329.996 288.155 330.886 290.499 330.823 292.916C330.612 297.737 329.522 302.479 327.606 306.908C327.939 306.393 328.23 305.853 328.476 305.292C331.969 297.304 333.774 288.679 333.777 279.96C333.777 266.41 324.361 257.571 310.844 257.571C287.276 257.571 282.554 278.151 272.614 300.154C262.3 322.999 243.357 347.709 195.586 347.709C145.951 347.709 94.9487 312.944 107.389 242.253C107.54 241.369 107.665 240.582 107.761 239.85C105.939 248.982 105.014 258.272 105 267.584C105.138 324.491 149.582 367.585 208.688 368.91Z'
fill='#352D8E'
/>
</svg>
)
}
export function DatabricksIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 241 266' fill='none' xmlns='http://www.w3.org/2000/svg'>

View File

@@ -0,0 +1,95 @@
import type { DagsterDeleteRunParams, DagsterDeleteRunResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface DeleteRunResult {
type: string
runId?: string
message?: string
}
const DELETE_RUN_MUTATION = `
mutation DeleteRun($runId: String!) {
deleteRun(runId: $runId) {
type: __typename
... on DeletePipelineRunSuccess {
runId
}
... on RunNotFoundError {
message
}
... on UnauthorizedError {
message
}
... on PythonError {
message
}
}
}
`
export const deleteRunTool: ToolConfig<DagsterDeleteRunParams, DagsterDeleteRunResponse> = {
id: 'dagster_delete_run',
name: 'Dagster Delete Run',
description: 'Permanently delete a Dagster run record.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
runId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the run to delete',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: DELETE_RUN_MUTATION,
variables: { runId: params.runId },
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ deleteRun?: unknown }>(response)
const result = data.data?.deleteRun as DeleteRunResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'DeletePipelineRunSuccess' && result.runId) {
return {
success: true,
output: { runId: result.runId },
}
}
throw new Error(`${result.type}: ${dagsterUnionErrorMessage(result, 'Delete run failed')}`)
},
outputs: {
runId: {
type: 'string',
description: 'The ID of the deleted run',
},
},
}

View File

@@ -0,0 +1,149 @@
import type { DagsterGetRunParams, DagsterGetRunResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
/** Fields selected on `runOrError` when the union resolves to `Run`. */
interface DagsterGetRunGraphqlRun {
runId: string
jobName: string | null
status: string
startTime: number | null
endTime: number | null
runConfigYaml: string | null
tags: Array<{ key: string; value: string }> | null
}
const GET_RUN_QUERY = `
query GetRun($runId: ID!) {
runOrError(runId: $runId) {
... on Run {
runId
jobName
status
startTime
endTime
runConfigYaml
tags {
key
value
}
}
... on RunNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const getRunTool: ToolConfig<DagsterGetRunParams, DagsterGetRunResponse> = {
id: 'dagster_get_run',
name: 'Dagster Get Run',
description: 'Get the status and details of a Dagster run by its ID.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3000)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
runId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the run to retrieve',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: GET_RUN_QUERY,
variables: { runId: params.runId },
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ runOrError?: unknown }>(response)
const raw = data.data?.runOrError
if (!raw || typeof raw !== 'object') throw new Error('Unexpected response from Dagster')
if (!('runId' in raw) || typeof (raw as { runId: unknown }).runId !== 'string') {
throw new Error(
dagsterUnionErrorMessage(raw as { message?: string }, 'Run not found or Dagster error')
)
}
const run = raw as DagsterGetRunGraphqlRun
return {
success: true,
output: {
runId: run.runId,
jobName: run.jobName ?? null,
status: run.status,
startTime: run.startTime ?? null,
endTime: run.endTime ?? null,
runConfigYaml: run.runConfigYaml ?? null,
tags: run.tags ?? null,
},
}
},
outputs: {
runId: {
type: 'string',
description: 'Run ID',
},
jobName: {
type: 'string',
description: 'Name of the job this run belongs to',
optional: true,
},
status: {
type: 'string',
description:
'Run status (QUEUED, NOT_STARTED, STARTING, MANAGED, STARTED, SUCCESS, FAILURE, CANCELING, CANCELED)',
},
startTime: {
type: 'number',
description: 'Run start time as Unix timestamp',
optional: true,
},
endTime: {
type: 'number',
description: 'Run end time as Unix timestamp',
optional: true,
},
runConfigYaml: {
type: 'string',
description: 'Run configuration as YAML',
optional: true,
},
tags: {
type: 'json',
description: 'Run tags as array of {key, value} objects',
optional: true,
},
},
}

View File

@@ -0,0 +1,166 @@
import type { DagsterGetRunLogsParams, DagsterGetRunLogsResponse } from '@/tools/dagster/types'
import { parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface DagsterRunEvent {
__typename?: string
message?: string
timestamp?: string
level?: string
stepKey?: string | null
eventType?: string | null
}
interface DagsterEventConnection {
events?: DagsterRunEvent[]
cursor?: string
hasMore?: boolean
}
const GET_RUN_LOGS_QUERY = `
query GetRunLogs($runId: ID!, $afterCursor: String, $limit: Int) {
logsForRun(runId: $runId, afterCursor: $afterCursor, limit: $limit) {
... on EventConnection {
events {
__typename
... on MessageEvent {
message
timestamp
level
stepKey
eventType
}
}
cursor
hasMore
}
... on RunNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const getRunLogsTool: ToolConfig<DagsterGetRunLogsParams, DagsterGetRunLogsResponse> = {
id: 'dagster_get_run_logs',
name: 'Dagster Get Run Logs',
description: 'Fetch execution event logs for a Dagster run.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
runId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the run to fetch logs for',
},
afterCursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Cursor for paginating through log events (from a previous response)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of log events to return',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => {
const variables: Record<string, unknown> = { runId: params.runId }
if (params.afterCursor) variables.afterCursor = params.afterCursor
if (params.limit != null) variables.limit = params.limit
return { query: GET_RUN_LOGS_QUERY, variables }
},
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ logsForRun?: unknown }>(response)
const result = data.data?.logsForRun as
| DagsterEventConnection
| { message?: string }
| undefined
if (!result || typeof result !== 'object') throw new Error('Unexpected response from Dagster')
if (!('events' in result)) {
const errResult = result as { message?: string }
throw new Error(errResult.message ?? 'Failed to fetch run logs')
}
const conn = result as DagsterEventConnection
const events = (conn.events ?? []).map((e) => ({
type: e.__typename ?? 'Unknown',
message: e.message ?? '',
timestamp: e.timestamp ?? '',
level: e.level ?? 'INFO',
stepKey: e.stepKey ?? null,
eventType: e.eventType ?? null,
}))
return {
success: true,
output: {
events,
cursor: conn.cursor ?? null,
hasMore: conn.hasMore ?? false,
},
}
},
outputs: {
events: {
type: 'json',
description: 'Array of log events (type, message, timestamp, level, stepKey, eventType)',
properties: {
type: { type: 'string', description: 'GraphQL typename of the event' },
message: { type: 'string', description: 'Human-readable log message' },
timestamp: { type: 'string', description: 'Event timestamp as a Unix epoch string' },
level: { type: 'string', description: 'Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)' },
stepKey: {
type: 'string',
description: 'Step key, if the event is step-scoped',
optional: true,
},
eventType: { type: 'string', description: 'Dagster event type enum value', optional: true },
},
},
cursor: {
type: 'string',
description: 'Cursor for fetching the next page of log events',
optional: true,
},
hasMore: {
type: 'boolean',
description: 'Whether more log events are available beyond this page',
},
},
}

View File

@@ -0,0 +1,31 @@
import { deleteRunTool } from '@/tools/dagster/delete_run'
import { getRunTool } from '@/tools/dagster/get_run'
import { getRunLogsTool } from '@/tools/dagster/get_run_logs'
import { launchRunTool } from '@/tools/dagster/launch_run'
import { listJobsTool } from '@/tools/dagster/list_jobs'
import { listRunsTool } from '@/tools/dagster/list_runs'
import { listSchedulesTool } from '@/tools/dagster/list_schedules'
import { listSensorsTool } from '@/tools/dagster/list_sensors'
import { reexecuteRunTool } from '@/tools/dagster/reexecute_run'
import { startScheduleTool } from '@/tools/dagster/start_schedule'
import { startSensorTool } from '@/tools/dagster/start_sensor'
import { stopScheduleTool } from '@/tools/dagster/stop_schedule'
import { stopSensorTool } from '@/tools/dagster/stop_sensor'
import { terminateRunTool } from '@/tools/dagster/terminate_run'
export const dagsterLaunchRunTool = launchRunTool
export const dagsterGetRunTool = getRunTool
export const dagsterListRunsTool = listRunsTool
export const dagsterListJobsTool = listJobsTool
export const dagsterTerminateRunTool = terminateRunTool
export const dagsterGetRunLogsTool = getRunLogsTool
export const dagsterReexecuteRunTool = reexecuteRunTool
export const dagsterDeleteRunTool = deleteRunTool
export const dagsterListSchedulesTool = listSchedulesTool
export const dagsterStartScheduleTool = startScheduleTool
export const dagsterStopScheduleTool = stopScheduleTool
export const dagsterListSensorsTool = listSensorsTool
export const dagsterStartSensorTool = startSensorTool
export const dagsterStopSensorTool = stopSensorTool
export * from './types'

View File

@@ -0,0 +1,222 @@
import type { DagsterLaunchRunParams, DagsterLaunchRunResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface LaunchRunResult {
type: string
run?: { runId: string }
message?: string
/** Present when type === 'InvalidStepError' */
invalidStepKey?: string
/** Present when type === 'InvalidOutputError' */
stepKey?: string
invalidOutputName?: string
/** Present when type === 'RunConfigValidationInvalid' */
errors?: Array<{ message: string }>
}
function buildLaunchRunMutation(hasConfig: boolean, hasTags: boolean) {
const varDefs = [
'$repositoryLocationName: String!',
'$repositoryName: String!',
'$jobName: String!',
]
if (hasConfig) varDefs.push('$runConfigData: RunConfigData')
if (hasTags) varDefs.push('$tags: [ExecutionTag!]')
const execParams = [
`selector: {
repositoryLocationName: $repositoryLocationName
repositoryName: $repositoryName
jobName: $jobName
}`,
]
if (hasConfig) execParams.push('runConfigData: $runConfigData')
if (hasTags) execParams.push('executionMetadata: { tags: $tags }')
return `
mutation LaunchRun(${varDefs.join(', ')}) {
launchRun(
executionParams: {
${execParams.join('\n ')}
}
) {
type: __typename
... on LaunchRunSuccess {
run {
runId
}
}
... on InvalidStepError {
__typename
invalidStepKey
}
... on InvalidOutputError {
__typename
stepKey
invalidOutputName
}
... on RunConfigValidationInvalid {
errors {
message
}
}
... on PipelineNotFoundError {
message
}
... on RunConflict {
message
}
... on UnauthorizedError {
message
}
... on InvalidSubsetError {
message
}
... on PresetNotFoundError {
message
}
... on ConflictingExecutionParamsError {
message
}
... on NoModeProvidedError {
message
}
... on PythonError {
message
}
}
}
`
}
export const launchRunTool: ToolConfig<DagsterLaunchRunParams, DagsterLaunchRunResponse> = {
id: 'dagster_launch_run',
name: 'Dagster Launch Run',
description: 'Launch a job run on a Dagster instance.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3000)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
repositoryLocationName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository location (code location) name',
},
repositoryName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository name within the code location',
},
jobName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the job to launch',
},
runConfigJson: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Run configuration as a JSON object (optional)',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Tags as a JSON array of {key, value} objects (optional)',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => {
const variables: Record<string, unknown> = {
repositoryLocationName: params.repositoryLocationName,
repositoryName: params.repositoryName,
jobName: params.jobName,
}
let hasConfig = false
if (params.runConfigJson) {
try {
variables.runConfigData = JSON.parse(params.runConfigJson)
hasConfig = true
} catch {
throw new Error('Invalid JSON in runConfigJson')
}
}
let hasTags = false
if (params.tags) {
try {
variables.tags = JSON.parse(params.tags)
hasTags = true
} catch {
throw new Error('Invalid JSON in tags')
}
}
return {
query: buildLaunchRunMutation(hasConfig, hasTags),
variables,
}
},
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ launchRun?: unknown }>(response)
const result = data.data?.launchRun as LaunchRunResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'LaunchRunSuccess' && result.run) {
return {
success: true,
output: { runId: result.run.runId },
}
}
if (result.type === 'InvalidStepError' && result.invalidStepKey) {
throw new Error(`InvalidStepError: invalid step key "${result.invalidStepKey}"`)
}
if (result.type === 'InvalidOutputError' && result.stepKey) {
throw new Error(
`InvalidOutputError: invalid output "${result.invalidOutputName ?? 'unknown'}" on step "${result.stepKey}"`
)
}
if (result.type === 'RunConfigValidationInvalid' && result.errors?.length) {
throw new Error(
`RunConfigValidationInvalid: ${result.errors.map((e) => e.message).join('; ')}`
)
}
throw new Error(`${result.type}: ${dagsterUnionErrorMessage(result, 'Launch run failed')}`)
},
outputs: {
runId: {
type: 'string',
description: 'The globally unique ID of the launched run',
},
},
}

View File

@@ -0,0 +1,103 @@
import type { DagsterBaseParams, DagsterListJobsResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
const LIST_JOBS_QUERY = `
query ListJobNames {
repositoriesOrError {
... on RepositoryConnection {
nodes {
name
jobs {
name
}
}
}
... on RepositoryNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const listJobsTool: ToolConfig<DagsterBaseParams, DagsterListJobsResponse> = {
id: 'dagster_list_jobs',
name: 'Dagster List Jobs',
description: 'List all jobs across repositories in a Dagster instance.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: () => ({
query: LIST_JOBS_QUERY,
variables: {},
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ repositoriesOrError?: unknown }>(response)
const result = data.data?.repositoriesOrError as
| { nodes?: Array<{ name: string; jobs?: Array<{ name: string }> }>; message?: string }
| undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (!Array.isArray(result.nodes)) {
throw new Error(dagsterUnionErrorMessage(result, 'List jobs failed'))
}
const jobs: Array<{ name: string; repositoryName: string }> = []
for (const repo of result.nodes) {
for (const job of repo.jobs ?? []) {
jobs.push({
name: job.name,
repositoryName: repo.name,
})
}
}
return {
success: true,
output: { jobs },
}
},
outputs: {
jobs: {
type: 'json',
description: 'Array of jobs with name and repositoryName',
properties: {
name: { type: 'string', description: 'Job name' },
repositoryName: { type: 'string', description: 'Repository name' },
},
},
},
}

View File

@@ -0,0 +1,155 @@
import type { DagsterListRunsParams, DagsterListRunsResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
/** Shape of each run in the `runsOrError` → `Runs.results` GraphQL selection set. */
interface DagsterListRunsGraphqlRow {
runId: string
jobName: string | null
status: string
tags: Array<{ key: string; value: string }> | null
startTime: number | null
endTime: number | null
}
function buildListRunsQuery(hasFilter: boolean) {
return `
query ListRuns($limit: Int${hasFilter ? ', $filter: RunsFilter' : ''}) {
runsOrError(limit: $limit${hasFilter ? ', filter: $filter' : ''}) {
... on Runs {
results {
runId
jobName
status
tags {
key
value
}
startTime
endTime
}
}
... on InvalidPipelineRunsFilterError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
}
export const listRunsTool: ToolConfig<DagsterListRunsParams, DagsterListRunsResponse> = {
id: 'dagster_list_runs',
name: 'Dagster List Runs',
description: 'List recent Dagster runs, optionally filtered by job name.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
jobName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter runs by job name (optional)',
},
statuses: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated run statuses to filter by, e.g. "SUCCESS,FAILURE" (optional)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of runs to return (default 20)',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => {
const filter: Record<string, unknown> = {}
if (params.jobName) filter.pipelineName = params.jobName
if (params.statuses) {
filter.statuses = params.statuses
.split(',')
.map((s: string) => s.trim())
.filter(Boolean)
}
const hasFilter = Object.keys(filter).length > 0
const variables: Record<string, unknown> = { limit: params.limit || 20 }
if (hasFilter) variables.filter = filter
return {
query: buildListRunsQuery(hasFilter),
variables,
}
},
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ runsOrError?: unknown }>(response)
const result = data.data?.runsOrError as
| { results?: DagsterListRunsGraphqlRow[]; message?: string }
| undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (!Array.isArray(result.results)) {
throw new Error(dagsterUnionErrorMessage(result, 'Dagster returned an error listing runs'))
}
const runs = result.results.map((r: DagsterListRunsGraphqlRow) => ({
runId: r.runId,
jobName: r.jobName ?? null,
status: r.status,
tags: r.tags ?? null,
startTime: r.startTime ?? null,
endTime: r.endTime ?? null,
}))
return {
success: true,
output: { runs },
}
},
outputs: {
runs: {
type: 'json',
description: 'Array of runs',
properties: {
runId: { type: 'string', description: 'Run ID' },
jobName: { type: 'string', description: 'Job name' },
status: { type: 'string', description: 'Run status' },
tags: { type: 'json', description: 'Run tags as array of {key, value} objects' },
startTime: { type: 'number', description: 'Start time as Unix timestamp' },
endTime: { type: 'number', description: 'End time as Unix timestamp' },
},
},
},
}

View File

@@ -0,0 +1,161 @@
import type {
DagsterListSchedulesParams,
DagsterListSchedulesResponse,
} from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface DagsterScheduleGraphql {
name: string
cronSchedule: string | null
pipelineName: string | null
description: string | null
executionTimezone: string | null
scheduleState?: {
id: string
status: string
} | null
}
function buildListSchedulesQuery(hasStatus: boolean) {
return `
query ListSchedules($repositorySelector: RepositorySelector!${hasStatus ? ', $scheduleStatus: InstigationStatus' : ''}) {
schedulesOrError(repositorySelector: $repositorySelector${hasStatus ? ', scheduleStatus: $scheduleStatus' : ''}) {
... on Schedules {
results {
name
cronSchedule
pipelineName
description
executionTimezone
scheduleState {
id
status
}
}
}
... on RepositoryNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
}
export const listSchedulesTool: ToolConfig<
DagsterListSchedulesParams,
DagsterListSchedulesResponse
> = {
id: 'dagster_list_schedules',
name: 'Dagster List Schedules',
description: 'List all schedules in a Dagster repository, optionally filtered by status.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
repositoryLocationName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository location (code location) name',
},
repositoryName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository name within the code location',
},
scheduleStatus: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter schedules by status: RUNNING or STOPPED (omit to return all)',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => {
const hasStatus = Boolean(params.scheduleStatus)
const variables: Record<string, unknown> = {
repositorySelector: {
repositoryLocationName: params.repositoryLocationName,
repositoryName: params.repositoryName,
},
}
if (hasStatus) variables.scheduleStatus = params.scheduleStatus
return { query: buildListSchedulesQuery(hasStatus), variables }
},
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ schedulesOrError?: unknown }>(response)
const result = data.data?.schedulesOrError as
| { results?: DagsterScheduleGraphql[]; message?: string }
| undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (!Array.isArray(result.results)) {
throw new Error(dagsterUnionErrorMessage(result, 'List schedules failed'))
}
const schedules = result.results.map((s) => ({
name: s.name,
cronSchedule: s.cronSchedule ?? null,
jobName: s.pipelineName ?? null,
status: s.scheduleState?.status ?? 'UNKNOWN',
id: s.scheduleState?.id ?? null,
description: s.description ?? null,
executionTimezone: s.executionTimezone ?? null,
}))
return {
success: true,
output: { schedules },
}
},
outputs: {
schedules: {
type: 'json',
description:
'Array of schedules (name, cronSchedule, jobName, status, id, description, executionTimezone)',
properties: {
name: { type: 'string', description: 'Schedule name' },
cronSchedule: { type: 'string', description: 'Cron expression for the schedule' },
jobName: { type: 'string', description: 'Job the schedule targets' },
status: { type: 'string', description: 'Schedule status: RUNNING or STOPPED' },
id: {
type: 'string',
description: 'Instigator state ID — use this to start or stop the schedule',
},
description: { type: 'string', description: 'Human-readable schedule description' },
executionTimezone: { type: 'string', description: 'Timezone for cron evaluation' },
},
},
},
}

View File

@@ -0,0 +1,150 @@
import type { DagsterListSensorsParams, DagsterListSensorsResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface DagsterSensorGraphql {
name: string
sensorType: string | null
description: string | null
sensorState?: {
id: string
status: string
} | null
}
function buildListSensorsQuery(hasStatus: boolean) {
return `
query ListSensors($repositorySelector: RepositorySelector!${hasStatus ? ', $sensorStatus: InstigationStatus' : ''}) {
sensorsOrError(repositorySelector: $repositorySelector${hasStatus ? ', sensorStatus: $sensorStatus' : ''}) {
... on Sensors {
results {
name
sensorType
description
sensorState {
id
status
}
}
}
... on RepositoryNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
}
export const listSensorsTool: ToolConfig<DagsterListSensorsParams, DagsterListSensorsResponse> = {
id: 'dagster_list_sensors',
name: 'Dagster List Sensors',
description: 'List all sensors in a Dagster repository, optionally filtered by status.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
repositoryLocationName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository location (code location) name',
},
repositoryName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository name within the code location',
},
sensorStatus: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter sensors by status: RUNNING or STOPPED (omit to return all)',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => {
const hasStatus = Boolean(params.sensorStatus)
const variables: Record<string, unknown> = {
repositorySelector: {
repositoryLocationName: params.repositoryLocationName,
repositoryName: params.repositoryName,
},
}
if (hasStatus) variables.sensorStatus = params.sensorStatus
return { query: buildListSensorsQuery(hasStatus), variables }
},
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ sensorsOrError?: unknown }>(response)
const result = data.data?.sensorsOrError as
| { results?: DagsterSensorGraphql[]; message?: string }
| undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (!Array.isArray(result.results)) {
throw new Error(dagsterUnionErrorMessage(result, 'List sensors failed'))
}
const sensors = result.results.map((s) => ({
name: s.name,
sensorType: s.sensorType ?? null,
status: s.sensorState?.status ?? 'UNKNOWN',
id: s.sensorState?.id ?? null,
description: s.description ?? null,
}))
return {
success: true,
output: { sensors },
}
},
outputs: {
sensors: {
type: 'json',
description: 'Array of sensors (name, sensorType, status, id, description)',
properties: {
name: { type: 'string', description: 'Sensor name' },
sensorType: {
type: 'string',
description:
'Sensor type (ASSET, AUTO_MATERIALIZE, FRESHNESS_POLICY, MULTI_ASSET, RUN_STATUS, STANDARD)',
},
status: { type: 'string', description: 'Sensor status: RUNNING or STOPPED' },
id: {
type: 'string',
description: 'Instigator state ID — use this to start or stop the sensor',
},
description: { type: 'string', description: 'Human-readable sensor description' },
},
},
},
}

View File

@@ -0,0 +1,158 @@
import type { DagsterReexecuteRunParams, DagsterReexecuteRunResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface ReexecuteRunResult {
type: string
run?: { runId: string }
message?: string
/** Returned by InvalidStepError */
invalidStepKey?: string
/** Returned by InvalidOutputError */
invalidOutputName?: string
stepKey?: string
/** Returned by RunConfigValidationInvalid */
errors?: Array<{ message: string }>
}
const REEXECUTE_RUN_MUTATION = `
mutation LaunchRunReexecution($parentRunId: String!, $strategy: ReexecutionStrategy!) {
launchRunReexecution(
reexecutionParams: {
parentRunId: $parentRunId
strategy: $strategy
}
) {
type: __typename
... on LaunchRunSuccess {
run {
runId
}
}
... on InvalidStepError {
invalidStepKey
}
... on InvalidOutputError {
stepKey
invalidOutputName
}
... on RunConfigValidationInvalid {
errors {
message
}
}
... on PipelineNotFoundError {
message
}
... on RunConflict {
message
}
... on UnauthorizedError {
message
}
... on InvalidSubsetError {
message
}
... on PresetNotFoundError {
message
}
... on ConflictingExecutionParamsError {
message
}
... on NoModeProvidedError {
message
}
... on PythonError {
message
}
}
}
`
export const reexecuteRunTool: ToolConfig<DagsterReexecuteRunParams, DagsterReexecuteRunResponse> =
{
id: 'dagster_reexecute_run',
name: 'Dagster Reexecute Run',
description: 'Reexecute an existing Dagster run, optionally resuming only from failed steps.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
parentRunId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the run to reexecute',
},
strategy: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Reexecution strategy: ALL_STEPS reruns everything, FROM_FAILURE resumes from failed steps, FROM_ASSET_FAILURE resumes from failed assets',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: REEXECUTE_RUN_MUTATION,
variables: {
parentRunId: params.parentRunId,
strategy: params.strategy,
},
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ launchRunReexecution?: unknown }>(response)
const result = data.data?.launchRunReexecution as ReexecuteRunResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'LaunchRunSuccess' && result.run) {
return {
success: true,
output: { runId: result.run.runId },
}
}
let detail: string
if (result.type === 'InvalidStepError' && result.invalidStepKey) {
detail = `Invalid step key: ${result.invalidStepKey}`
} else if (result.type === 'InvalidOutputError' && result.invalidOutputName) {
detail = `Invalid output "${result.invalidOutputName}" on step "${result.stepKey}"`
} else if (result.type === 'RunConfigValidationInvalid' && result.errors?.length) {
detail = result.errors.map((e) => e.message).join('; ')
} else {
detail = dagsterUnionErrorMessage(result, 'Reexecute run failed')
}
throw new Error(`${result.type}: ${detail}`)
},
outputs: {
runId: {
type: 'string',
description: 'The ID of the newly launched reexecution run',
},
},
}

View File

@@ -0,0 +1,135 @@
import type {
DagsterScheduleMutationResponse,
DagsterStartScheduleParams,
} from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface ScheduleMutationResult {
type: string
scheduleState?: {
id: string
status: string
}
message?: string
}
const START_SCHEDULE_MUTATION = `
mutation StartSchedule($scheduleSelector: ScheduleSelector!) {
startSchedule(scheduleSelector: $scheduleSelector) {
type: __typename
... on ScheduleStateResult {
scheduleState {
id
status
}
}
... on UnauthorizedError {
__typename
message
}
... on ScheduleNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const startScheduleTool: ToolConfig<
DagsterStartScheduleParams,
DagsterScheduleMutationResponse
> = {
id: 'dagster_start_schedule',
name: 'Dagster Start Schedule',
description: 'Enable (start) a schedule in a Dagster repository.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
repositoryLocationName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository location (code location) name',
},
repositoryName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository name within the code location',
},
scheduleName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the schedule to start',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: START_SCHEDULE_MUTATION,
variables: {
scheduleSelector: {
repositoryLocationName: params.repositoryLocationName,
repositoryName: params.repositoryName,
scheduleName: params.scheduleName,
},
},
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ startSchedule?: unknown }>(response)
const result = data.data?.startSchedule as ScheduleMutationResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'ScheduleStateResult' && result.scheduleState) {
return {
success: true,
output: {
id: result.scheduleState.id,
status: result.scheduleState.status,
},
}
}
throw new Error(`${result.type}: ${dagsterUnionErrorMessage(result, 'Start schedule failed')}`)
},
outputs: {
id: {
type: 'string',
description: 'Instigator state ID of the schedule',
},
status: {
type: 'string',
description: 'Updated schedule status (RUNNING or STOPPED)',
},
},
}

View File

@@ -0,0 +1,130 @@
import type { DagsterSensorMutationResponse, DagsterStartSensorParams } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface SensorMutationResult {
type: string
sensorState?: {
id: string
status: string
}
message?: string
}
const START_SENSOR_MUTATION = `
mutation StartSensor($sensorSelector: SensorSelector!) {
startSensor(sensorSelector: $sensorSelector) {
type: __typename
... on Sensor {
sensorState {
id
status
}
}
... on SensorNotFoundError {
__typename
message
}
... on UnauthorizedError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const startSensorTool: ToolConfig<DagsterStartSensorParams, DagsterSensorMutationResponse> =
{
id: 'dagster_start_sensor',
name: 'Dagster Start Sensor',
description: 'Enable (start) a sensor in a Dagster repository.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
repositoryLocationName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository location (code location) name',
},
repositoryName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Repository name within the code location',
},
sensorName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the sensor to start',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: START_SENSOR_MUTATION,
variables: {
sensorSelector: {
repositoryLocationName: params.repositoryLocationName,
repositoryName: params.repositoryName,
sensorName: params.sensorName,
},
},
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ startSensor?: unknown }>(response)
const result = data.data?.startSensor as SensorMutationResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'Sensor' && result.sensorState) {
return {
success: true,
output: {
id: result.sensorState.id,
status: result.sensorState.status,
},
}
}
throw new Error(`${result.type}: ${dagsterUnionErrorMessage(result, 'Start sensor failed')}`)
},
outputs: {
id: {
type: 'string',
description: 'Instigator state ID of the sensor',
},
status: {
type: 'string',
description: 'Updated sensor status (RUNNING or STOPPED)',
},
},
}

View File

@@ -0,0 +1,118 @@
import type {
DagsterScheduleMutationResponse,
DagsterStopScheduleParams,
} from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface ScheduleMutationResult {
type: string
scheduleState?: {
id: string
status: string
}
message?: string
}
const STOP_SCHEDULE_MUTATION = `
mutation StopSchedule($id: String) {
stopRunningSchedule(id: $id) {
type: __typename
... on ScheduleStateResult {
scheduleState {
id
status
}
}
... on UnauthorizedError {
__typename
message
}
... on ScheduleNotFoundError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const stopScheduleTool: ToolConfig<
DagsterStopScheduleParams,
DagsterScheduleMutationResponse
> = {
id: 'dagster_stop_schedule',
name: 'Dagster Stop Schedule',
description: 'Disable (stop) a running schedule in Dagster.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
instigationStateId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'InstigationState ID of the schedule to stop — available from dagster_list_schedules output',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: STOP_SCHEDULE_MUTATION,
variables: { id: params.instigationStateId },
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ stopRunningSchedule?: unknown }>(response)
const result = data.data?.stopRunningSchedule as ScheduleMutationResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'ScheduleStateResult' && result.scheduleState) {
return {
success: true,
output: {
id: result.scheduleState.id,
status: result.scheduleState.status,
},
}
}
throw new Error(`${result.type}: ${dagsterUnionErrorMessage(result, 'Stop schedule failed')}`)
},
outputs: {
id: {
type: 'string',
description: 'Instigator state ID of the schedule',
},
status: {
type: 'string',
description: 'Updated schedule status (RUNNING or STOPPED)',
},
},
}

View File

@@ -0,0 +1,108 @@
import type { DagsterSensorMutationResponse, DagsterStopSensorParams } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
interface StopSensorResult {
type: string
instigationState?: {
id: string
status: string
}
message?: string
}
const STOP_SENSOR_MUTATION = `
mutation StopSensor($id: String) {
stopSensor(id: $id) {
type: __typename
... on StopSensorMutationResult {
instigationState {
id
status
}
}
... on UnauthorizedError {
__typename
message
}
... on PythonError {
__typename
message
}
}
}
`
export const stopSensorTool: ToolConfig<DagsterStopSensorParams, DagsterSensorMutationResponse> = {
id: 'dagster_stop_sensor',
name: 'Dagster Stop Sensor',
description: 'Disable (stop) a running sensor in Dagster.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
instigationStateId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'InstigationState ID of the sensor to stop — available from dagster_list_sensors output',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: STOP_SENSOR_MUTATION,
variables: { id: params.instigationStateId },
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ stopSensor?: unknown }>(response)
const result = data.data?.stopSensor as StopSensorResult | undefined
if (!result) throw new Error('Unexpected response from Dagster')
if (result.type === 'StopSensorMutationResult' && result.instigationState) {
return {
success: true,
output: {
id: result.instigationState.id,
status: result.instigationState.status,
},
}
}
throw new Error(`${result.type}: ${dagsterUnionErrorMessage(result, 'Stop sensor failed')}`)
},
outputs: {
id: {
type: 'string',
description: 'Instigator state ID of the sensor',
},
status: {
type: 'string',
description: 'Updated sensor status (RUNNING or STOPPED)',
},
},
}

View File

@@ -0,0 +1,126 @@
import type { DagsterTerminateRunParams, DagsterTerminateRunResponse } from '@/tools/dagster/types'
import { dagsterUnionErrorMessage, parseDagsterGraphqlResponse } from '@/tools/dagster/utils'
import type { ToolConfig } from '@/tools/types'
/** Fields returned from `terminateRun` for all union members. */
interface DagsterTerminateRunPayload {
__typename?: string
run?: { runId: string }
message?: string
}
const TERMINATE_RUN_MUTATION = `
mutation TerminateRun($runId: String!) {
terminateRun(runId: $runId) {
__typename
... on TerminateRunSuccess {
run {
runId
}
}
... on TerminateRunFailure {
run {
runId
}
message
}
... on RunNotFoundError {
message
}
... on UnauthorizedError {
message
}
... on PythonError {
message
}
}
}
`
export const terminateRunTool: ToolConfig<DagsterTerminateRunParams, DagsterTerminateRunResponse> =
{
id: 'dagster_terminate_run',
name: 'Dagster Terminate Run',
description: 'Terminate an in-progress Dagster run.',
version: '1.0.0',
params: {
host: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Dagster host URL (e.g., https://myorg.dagster.cloud/prod or http://localhost:3001)',
},
apiKey: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Dagster+ API token (leave blank for OSS / self-hosted)',
},
runId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the run to terminate',
},
},
request: {
url: (params) => `${params.host.replace(/\/$/, '')}/graphql`,
method: 'POST',
headers: (params) => {
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
if (params.apiKey) headers['Dagster-Cloud-Api-Token'] = params.apiKey
return headers
},
body: (params) => ({
query: TERMINATE_RUN_MUTATION,
variables: { runId: params.runId },
}),
},
transformResponse: async (response: Response) => {
const data = await parseDagsterGraphqlResponse<{ terminateRun?: DagsterTerminateRunPayload }>(
response
)
const result = data.data?.terminateRun
if (!result) throw new Error('Unexpected response from Dagster')
if (result.__typename === 'TerminateRunSuccess' && result.run?.runId) {
return {
success: true,
output: {
success: true,
runId: result.run.runId,
message: null,
},
}
}
if (result.__typename === 'TerminateRunFailure') {
throw new Error(
`TerminateRunFailure: ${dagsterUnionErrorMessage(result, 'Terminate run failed')}`
)
}
throw new Error(dagsterUnionErrorMessage(result, 'Terminate run failed'))
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the run was successfully terminated',
},
runId: {
type: 'string',
description: 'The ID of the terminated run',
},
message: {
type: 'string',
description: 'Error or status message if termination failed',
optional: true,
},
},
}

View File

@@ -0,0 +1,204 @@
import type { ToolResponse } from '@/tools/types'
export interface DagsterBaseParams {
host: string
apiKey?: string
}
export interface DagsterLaunchRunParams extends DagsterBaseParams {
repositoryLocationName: string
repositoryName: string
jobName: string
runConfigJson?: string
tags?: string
}
export interface DagsterLaunchRunResponse extends ToolResponse {
output: {
runId: string
}
}
export interface DagsterGetRunParams extends DagsterBaseParams {
runId: string
}
export interface DagsterGetRunResponse extends ToolResponse {
output: {
runId: string
jobName: string | null
status: string
startTime: number | null
endTime: number | null
runConfigYaml: string | null
tags: Array<{ key: string; value: string }> | null
}
}
export interface DagsterListRunsParams extends DagsterBaseParams {
jobName?: string
statuses?: string
limit?: number
}
export interface DagsterListRunsResponse extends ToolResponse {
output: {
runs: Array<{
runId: string
jobName: string | null
status: string
tags: Array<{ key: string; value: string }> | null
startTime: number | null
endTime: number | null
}>
}
}
export interface DagsterListJobsResponse extends ToolResponse {
output: {
jobs: Array<{
name: string
repositoryName: string
}>
}
}
export interface DagsterTerminateRunParams extends DagsterBaseParams {
runId: string
}
export interface DagsterTerminateRunResponse extends ToolResponse {
output: {
success: boolean
runId: string
message: string | null
}
}
export interface DagsterGetRunLogsParams extends DagsterBaseParams {
runId: string
afterCursor?: string
limit?: number
}
export interface DagsterGetRunLogsResponse extends ToolResponse {
output: {
events: Array<{
type: string
message: string
timestamp: string
level: string
stepKey: string | null
eventType: string | null
}>
cursor: string | null
hasMore: boolean
}
}
export interface DagsterReexecuteRunParams extends DagsterBaseParams {
parentRunId: string
strategy: string
}
export interface DagsterReexecuteRunResponse extends ToolResponse {
output: {
runId: string
}
}
export interface DagsterDeleteRunParams extends DagsterBaseParams {
runId: string
}
export interface DagsterDeleteRunResponse extends ToolResponse {
output: {
runId: string
}
}
export interface DagsterListSchedulesParams extends DagsterBaseParams {
repositoryLocationName: string
repositoryName: string
scheduleStatus?: string
}
export interface DagsterListSchedulesResponse extends ToolResponse {
output: {
schedules: Array<{
name: string
cronSchedule: string | null
jobName: string | null
status: string
id: string | null
description: string | null
executionTimezone: string | null
}>
}
}
export interface DagsterStartScheduleParams extends DagsterBaseParams {
repositoryLocationName: string
repositoryName: string
scheduleName: string
}
export interface DagsterScheduleMutationResponse extends ToolResponse {
output: {
id: string
status: string
}
}
export interface DagsterStopScheduleParams extends DagsterBaseParams {
instigationStateId: string
}
export interface DagsterListSensorsParams extends DagsterBaseParams {
repositoryLocationName: string
repositoryName: string
sensorStatus?: string
}
export interface DagsterListSensorsResponse extends ToolResponse {
output: {
sensors: Array<{
name: string
sensorType: string | null
status: string
id: string | null
description: string | null
}>
}
}
export interface DagsterStartSensorParams extends DagsterBaseParams {
repositoryLocationName: string
repositoryName: string
sensorName: string
}
export interface DagsterSensorMutationResponse extends ToolResponse {
output: {
id: string
status: string
}
}
export interface DagsterStopSensorParams extends DagsterBaseParams {
instigationStateId: string
}
export type DagsterResponse =
| DagsterLaunchRunResponse
| DagsterGetRunResponse
| DagsterListRunsResponse
| DagsterListJobsResponse
| DagsterTerminateRunResponse
| DagsterGetRunLogsResponse
| DagsterReexecuteRunResponse
| DagsterDeleteRunResponse
| DagsterListSchedulesResponse
| DagsterScheduleMutationResponse
| DagsterListSensorsResponse
| DagsterSensorMutationResponse

View File

@@ -0,0 +1,41 @@
/**
* Parses a Dagster GraphQL JSON body and throws if the HTTP status is not OK or the payload
* contains top-level GraphQL errors.
*
* Field errors should be requested with `... on Error { __typename message }` (or at least
* `message`) so union failures are not returned as empty objects.
*/
export async function parseDagsterGraphqlResponse<TData extends Record<string, unknown>>(
response: Response
): Promise<{ data?: TData }> {
let payload: {
data?: TData
errors?: ReadonlyArray<{ message?: string }>
}
try {
payload = (await response.json()) as {
data?: TData
errors?: ReadonlyArray<{ message?: string }>
}
} catch {
throw new Error('Invalid JSON response from Dagster')
}
if (!response.ok) {
throw new Error(payload.errors?.[0]?.message || 'Dagster GraphQL request failed')
}
if (payload.errors?.length) {
throw new Error(payload.errors[0]?.message ?? 'Dagster GraphQL request failed')
}
return { data: payload.data }
}
/**
* Message from a field that includes `... on Error { message }`, or a fallback when the
* payload is not a GraphQL `Error` type with a string message.
*/
export function dagsterUnionErrorMessage(
result: { message?: string } | undefined,
fallback: string
): string {
return typeof result?.message === 'string' ? result.message : fallback
}

View File

@@ -361,6 +361,22 @@ import {
cursorStopAgentTool,
cursorStopAgentV2Tool,
} from '@/tools/cursor'
import {
dagsterDeleteRunTool,
dagsterGetRunLogsTool,
dagsterGetRunTool,
dagsterLaunchRunTool,
dagsterListJobsTool,
dagsterListRunsTool,
dagsterListSchedulesTool,
dagsterListSensorsTool,
dagsterReexecuteRunTool,
dagsterStartScheduleTool,
dagsterStartSensorTool,
dagsterStopScheduleTool,
dagsterStopSensorTool,
dagsterTerminateRunTool,
} from '@/tools/dagster'
import {
databricksCancelRunTool,
databricksExecuteSqlTool,
@@ -3444,6 +3460,20 @@ export const tools: Record<string, ToolConfig> = {
devin_get_session: devinGetSessionTool,
devin_list_sessions: devinListSessionsTool,
devin_send_message: devinSendMessageTool,
dagster_delete_run: dagsterDeleteRunTool,
dagster_get_run: dagsterGetRunTool,
dagster_get_run_logs: dagsterGetRunLogsTool,
dagster_launch_run: dagsterLaunchRunTool,
dagster_list_jobs: dagsterListJobsTool,
dagster_list_runs: dagsterListRunsTool,
dagster_list_schedules: dagsterListSchedulesTool,
dagster_list_sensors: dagsterListSensorsTool,
dagster_reexecute_run: dagsterReexecuteRunTool,
dagster_start_schedule: dagsterStartScheduleTool,
dagster_start_sensor: dagsterStartSensorTool,
dagster_stop_schedule: dagsterStopScheduleTool,
dagster_stop_sensor: dagsterStopSensorTool,
dagster_terminate_run: dagsterTerminateRunTool,
databricks_cancel_run: databricksCancelRunTool,
databricks_execute_sql: databricksExecuteSqlTool,
databricks_get_run: databricksGetRunTool,