Loading the notebook…
Loading the notebook…
Notebooks · Specialist agents · 51
End-to-end workflow:
Its imports and arguments are checked against shipit-agent 3.0. The outputs were saved when it was written, for an earlier release.
from pathlib import Path
def _find_notebooks_dir() -> Path:
cwd = Path.cwd().resolve()
if cwd.name == 'notebooks':
return cwd
candidate = cwd / 'notebooks'
return candidate if candidate.is_dir() else cwd
WORKSPACE = _find_notebooks_dir() / '_support_workspace'
WORKSPACE.mkdir(parents=True, exist_ok=True)
print('workspace:', WORKSPACE)
# from shipit_agent.llms import build_llm_from_settings
# llm = build_llm_from_settings({'provider': 'bedrock',
# 'model': 'bedrock/anthropic.claude-sonnet-4-5-v2:0'}, provider='bedrock')
# llm = build_llm_from_settings({'provider': 'litellm',
# 'model': 'openai/gpt-4o'}, provider='litellm')
# from shipit_agent.llms import LiteLLMProxyChatLLM
# llm = LiteLLMProxyChatLLM(model='gpt-4o',
# api_base='https://litellm.internal', api_key='sk-proxy')
from shipit_agent.llms import SimpleEchoLLM
llm = SimpleEchoLLM()
print('llm:', type(llm).__name__)
from shipit_agent.integrations import CredentialRecord, InMemoryCredentialStore
from shipit_agent.tools.zendesk import ZendeskTool
store = InMemoryCredentialStore()
store.set(CredentialRecord(
key='zendesk', provider='zendesk',
secrets={'token': 'zd-demo', 'email': '[email]'},
metadata={'base_url': 'https://acme.zendesk.com',
'auth_scheme': 'Basic'},
))
zd = ZendeskTool(credential_store=store)
_TICKETS = [
{'id': 9001, 'subject': 'Card declined on Pro upgrade', 'status': 'open',
'priority': 'high', 'tags': ['billing', 'card'],
'requester_id': 501, 'screenshot_url': 'https://example.com/zd/ticket-9001.png'},
{'id': 9002, 'subject': 'Dashboard shows 502 after login', 'status': 'open',
'priority': 'urgent', 'tags': ['outage', 'frontend'],
'requester_id': 502},
{'id': 9003, 'subject': 'Invoice PDF export missing VAT line', 'status': 'open',
'priority': 'normal', 'tags': ['billing', 'invoice', 'export'],
'requester_id': 503},
{'id': 9004, 'subject': 'Slack integration disconnects every hour', 'status': 'open',
'priority': 'high', 'tags': ['integrations', 'slack'],
'requester_id': 504},
]
def _fake_zd(*, record, method, path, query=None, body=None):
if path == '/api/v2/search.json':
return {'results': _TICKETS, 'count': len(_TICKETS)}
if path.startswith('/api/v2/tickets/'):
tid = int(path.rsplit('/', 1)[-1].split('.')[0])
for t in _TICKETS:
if t['id'] == tid:
return {'ticket': t}
return {}
zd._request_json = _fake_zd
print('zendesk stub installed')
from shipit_agent.tools.base import ToolContext
ctx = ToolContext(prompt='support triage', state={'credential_store': store})
tickets_out = zd.run(ctx, action='search_tickets',
query='status:open priority>=high')
print(tickets_out.text)
tickets = tickets_out.metadata.get('items') or []
from collections import Counter
def categorize(tags):
for t in tags:
if t in ('billing', 'invoice'):
return 'Billing'
if t in ('outage', 'frontend', 'backend'):
return 'Reliability'
if t in ('integrations', 'slack', 'webhook'):
return 'Integrations'
return 'Other'
counts = Counter(categorize(t.get('tags', [])) for t in tickets)
for cat, n in counts.most_common():
print(f'{cat:<14} {n}')
One ticket has a customer screenshot attached. We ask the vision tool to read the on-screen error text and summarise it.
from shipit_agent.tools.vision import VisionTool
vision = VisionTool(llm=llm)
target = next(t for t in tickets if t.get('screenshot_url'))
v = vision.run(ctx, image=target['screenshot_url'],
prompt='Extract the exact error message shown on the screen.')
print(f"ticket #{target['id']}")
print(f"vision text: {v.text[:240]}")
from shipit_agent.tools.dashboard_render import DashboardRenderTool
dash = DashboardRenderTool(workspace_root=WORKSPACE)
metric_items = [
{'label': 'Open tickets', 'value': str(len(tickets))},
{'label': 'Urgent', 'value': str(sum(1 for t in tickets if t.get('priority') == 'urgent'))},
{'label': 'High', 'value': str(sum(1 for t in tickets if t.get('priority') == 'high'))},
]
palette = ['#d85a30', '#185fa5', '#534ab7', '#888888']
bars = [
{'label': cat, 'pct': int(round(n / max(1, len(tickets)) * 100)),
'color': palette[i % len(palette)]}
for i, (cat, n) in enumerate(counts.most_common())
]
timeline = [
{'period': f'#{t["id"]}', 'head': t['subject'],
'desc': f"priority={t['priority']} tags={','.join(t['tags'])}",
'dot_color': '#d85a30' if t['priority'] == 'urgent' else '#185fa5',
'tags': [{'text': t['priority'], 'color': 'red' if t['priority']=='urgent' else 'blue'}]}
for t in tickets
]
result = dash.run(
ToolContext(prompt='support triage',
state={'artifact_workspace_root': str(WORKSPACE)}),
title='Support Triage — 2026-04-24',
subtitle='Open tickets, priority>=high',
lang='en',
sections=[
{'type': 'metrics', 'title': 'Queue', 'columns': 3, 'items': metric_items},
{'type': 'bars', 'title': 'By category', 'items': bars},
{'type': 'timeline', 'title': 'Open ticket queue', 'items': timeline},
{'type': 'verdict', 'title': 'Triage verdict',
'text': ('**Reliability is the breakout category.** One urgent 502 '
'needs an on-call page; billing churn is steady.')},
],
export=True,
)
print(result.text)
print('artifact path:', result.metadata.get('path'))
docs-app/content/source/tools/zendesk.md for the full Zendesk action surface (macros, comments, assignment).VerifierTool + autopilot loop so tickets are auto-triaged and routed to the right squad every 5 minutes.