Call an Integration Tool Without an Agent
Call one integration operation with values already available in a workflow run.
Use a tool step when the workflow already knows which integration operation to call and which values to send. Shipfox calls the tool and saves its response as step outputs. An agent does not choose the operation.
This guide posts a Slack message. For another tool, replace the tool id, the slug of the integration connection, inputs, and output mapping.
Before you begin
You need:
- An integration connection for a provider with tools. Find a provider in the integrations catalog.
- The slug of the integration connection. This guide uses
slack_acme. - Values for each required input. Open the provider in the integrations catalog, then select Tools to find the input names and descriptions.
- A Slack channel ID for this example. Invite the Shipfox app to the channel.
Call the tool
Choose the operation
Open the provider's tools page from the integrations catalog. Choose an operation and copy its id. Record its required inputs and whether it reads or writes data.
This guide uses send_message from the Slack
tools page.
Create the workflow
Create .shipfox/workflows/call-a-tool.yml. Replace the slug of the
integration connection, tool id, and inputs. This is a complete workflow:
# yaml-language-server: $schema=https://www.shipfox.io/docs/workflow.schema.json
name: Call a tool
runner: shipfox
triggers:
manual:
source: manual
jobs:
call:
steps:
- key: call_tool
tool: send_message # Replace with an id from the provider's tools page.
connection: slack_acme # Replace with the slug of your integration connection.
with: # Replace with the tool's inputs.
channel_id: C0ABC12345
message: "Run #${{ run.number }} of ${{ workflow.name }} started."
outputs:
ts: ${{ result.ts }} # Replace with a field from the tool result.
- env:
TOOL_RESULT: ${{ steps.call_tool.outputs.ts }}
run: printf 'Tool result field: %s\n' "$TOOL_RESULT"Adapt these fields:
| Field | Value |
|---|---|
tool | The id from the provider's tools page. GitHub tools use family.method. |
connection | The slug of the integration connection. Omit this field only when the tool uses the project's source integration connection. |
with | The tool inputs, using the names from the provider's tools page. String values can include ${{ }} expressions. |
outputs | Fields from the tool result that later steps need. The complete response remains available as steps.<key>.outputs.result. |
See Tool step fields for the complete contract.
Verify the result
Start the workflow
Select Run, then open the new run.
Inspect the tool call
Open the tool step. Confirm that Arguments shows the resolved inputs. Confirm that Result shows the provider response.
Inspect the mapped output
Open the run step. Confirm that its log contains the mapped result field.
Check Slack
Open the Slack channel. Confirm that the message appears once.
If Shipfox denies the tool call
Check the provider permissions for the integration connection. For this example, confirm that the Shipfox app is in the Slack channel. Then inspect the integration connection in Settings → Integrations.
Accept an expected failure
A gate on a tool step decides the step result, even when the tool call failed.
Read step.error to tell one failure from another. It holds the code of the
failed call, such as not-found or rate-limited, and the provider status
when there is one. It is null when the call did not fail.
- key: find_issue
tool: get_issue
connection: linear_acme
with:
id: ENG-999999
gate:
success: step.status == "failed" && step.error.code == "not-found"This step passes when the issue does not exist and fails for any other error.
Guard step.error.status with has(step.error.status), because some failures
have no status.
Wait for a change to apply
A provider can apply a change after a delay. For example, GitHub can take some seconds to cancel a workflow run. To wait for the change, read the data again until the change is there:
- key: cancel
tool: actions_run_trigger.cancel_workflow_run
connection: github_acme
with:
owner: acme
repo: api
run_id: ${{ inputs.run_id }}
- key: wait
run: sleep 10
- key: check_run
tool: actions_get.get_workflow_run
connection: github_acme
with:
owner: acme
repo: api
resource_id: ${{ string(inputs.run_id) }}
gate:
success: step.status == "succeeded" && step.outputs.result.status == "completed"
on_failure:
restart_from: wait
max_attempts: 12This is what happens:
cancelcancels the run. This step runs one time.waitwaits 10 seconds.check_runreads the run.- If the run is not complete, the job goes back to
wait.
The job reads the run a maximum of 12 times. If the run is still not complete,
the job fails with restart_exhausted.
A tool step can send the job back to an earlier step only when it reads data. If the gate of a tool step that writes data fails, the job fails.
To pass a tool result to a later step, read it as steps.<key>.outputs. To
let an agent choose operations, post a pull-request
review.