Showing preview only (5,012K chars total). Download the full file or copy to clipboard to get everything.
Repository: rowboatlabs/rowboat
Branch: main
Commit: 983a4c578f61
Files: 893
Total size: 4.6 MB
Directory structure:
gitextract_kg5bbks8/
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── electron-build.yml
│ ├── rowboat-build.yml
│ └── x-publish.yml
├── .gitignore
├── CLAUDE.md
├── Dockerfile.qdrant
├── LICENSE
├── README.md
├── apps/
│ ├── cli/
│ │ ├── .gitignore
│ │ ├── bin/
│ │ │ └── app.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── agents/
│ │ │ │ ├── agents.ts
│ │ │ │ ├── repo.ts
│ │ │ │ └── runtime.ts
│ │ │ ├── app.ts
│ │ │ ├── application/
│ │ │ │ ├── assistant/
│ │ │ │ │ ├── agent.ts
│ │ │ │ │ ├── instructions.ts
│ │ │ │ │ ├── runtime-context.ts
│ │ │ │ │ └── skills/
│ │ │ │ │ ├── builtin-tools/
│ │ │ │ │ │ └── skill.ts
│ │ │ │ │ ├── deletion-guardrails/
│ │ │ │ │ │ └── skill.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── mcp-integration/
│ │ │ │ │ │ └── skill.ts
│ │ │ │ │ ├── workflow-authoring/
│ │ │ │ │ │ └── skill.ts
│ │ │ │ │ └── workflow-run-ops/
│ │ │ │ │ └── skill.ts
│ │ │ │ └── lib/
│ │ │ │ ├── builtin-tools.ts
│ │ │ │ ├── bus.ts
│ │ │ │ ├── command-executor.ts
│ │ │ │ ├── exec-tool.ts
│ │ │ │ ├── id-gen.ts
│ │ │ │ ├── message-queue.ts
│ │ │ │ ├── random-id.ts
│ │ │ │ └── stream-renderer.ts
│ │ │ ├── config/
│ │ │ │ ├── config.ts
│ │ │ │ └── security.ts
│ │ │ ├── di/
│ │ │ │ └── container.ts
│ │ │ ├── entities/
│ │ │ │ ├── example.ts
│ │ │ │ ├── llm-step-events.ts
│ │ │ │ ├── message.ts
│ │ │ │ └── run-events.ts
│ │ │ ├── examples/
│ │ │ │ ├── index.ts
│ │ │ │ └── twitter-podcast.json
│ │ │ ├── knowledge/
│ │ │ │ ├── sync_calendar.ts
│ │ │ │ └── sync_gmail.ts
│ │ │ ├── mcp/
│ │ │ │ ├── mcp.ts
│ │ │ │ ├── repo.ts
│ │ │ │ └── schema.ts
│ │ │ ├── models/
│ │ │ │ ├── models.ts
│ │ │ │ └── repo.ts
│ │ │ ├── runs/
│ │ │ │ ├── lock.ts
│ │ │ │ ├── repo.ts
│ │ │ │ └── runs.ts
│ │ │ ├── scripts/
│ │ │ │ └── migrate-agents.ts
│ │ │ ├── server.ts
│ │ │ ├── shared/
│ │ │ │ └── prefix-logger.ts
│ │ │ └── tui/
│ │ │ ├── api.ts
│ │ │ ├── index.tsx
│ │ │ └── ui.tsx
│ │ ├── todo.md
│ │ └── tsconfig.json
│ ├── docs/
│ │ ├── .gitignore
│ │ ├── docs/
│ │ │ ├── development/
│ │ │ │ ├── contribution-guide.mdx
│ │ │ │ └── roadmap.mdx
│ │ │ └── getting-started/
│ │ │ ├── introduction.mdx
│ │ │ ├── license.mdx
│ │ │ └── quickstart.mdx
│ │ └── docs.json
│ ├── experimental/
│ │ ├── chat_widget/
│ │ │ ├── .dockerignore
│ │ │ ├── .eslintrc.json
│ │ │ ├── .gitignore
│ │ │ ├── Dockerfile
│ │ │ ├── README.md
│ │ │ ├── app/
│ │ │ │ ├── api/
│ │ │ │ │ └── bootstrap.js/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── app.tsx
│ │ │ │ ├── globals.css
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── markdown-content.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ └── providers.tsx
│ │ │ ├── next.config.mjs
│ │ │ ├── package.json
│ │ │ ├── postcss.config.mjs
│ │ │ ├── public/
│ │ │ │ └── bootstrap.template.js
│ │ │ ├── tailwind.config.ts
│ │ │ └── tsconfig.json
│ │ ├── simulation_runner/
│ │ │ ├── Dockerfile
│ │ │ ├── __init__.py
│ │ │ ├── db.py
│ │ │ ├── requirements.txt
│ │ │ ├── scenario_types.py
│ │ │ ├── service.py
│ │ │ └── simulation.py
│ │ └── tools_webhook/
│ │ ├── Dockerfile
│ │ ├── __init__.py
│ │ ├── app.py
│ │ ├── function_map.py
│ │ ├── requirements.txt
│ │ ├── tests/
│ │ │ ├── __init__.py
│ │ │ ├── test_app.py
│ │ │ └── test_tool_caller.py
│ │ └── tool_caller.py
│ ├── python-sdk/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── pyproject.toml
│ │ ├── requirements.txt
│ │ └── src/
│ │ └── rowboat/
│ │ ├── __init__.py
│ │ ├── client.py
│ │ └── schema.py
│ ├── rowboat/
│ │ ├── .dockerignore
│ │ ├── .eslintrc.json
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ ├── README.md
│ │ ├── app/
│ │ │ ├── actions/
│ │ │ │ ├── assistant-templates.actions.ts
│ │ │ │ ├── auth.actions.ts
│ │ │ │ ├── billing.actions.ts
│ │ │ │ ├── composio.actions.ts
│ │ │ │ ├── conversation.actions.ts
│ │ │ │ ├── copilot.actions.ts
│ │ │ │ ├── custom-mcp-server.actions.ts
│ │ │ │ ├── data-source.actions.ts
│ │ │ │ ├── job.actions.ts
│ │ │ │ ├── playground-chat.actions.ts
│ │ │ │ ├── project.actions.ts
│ │ │ │ ├── recurring-job-rules.actions.ts
│ │ │ │ ├── scheduled-job-rules.actions.ts
│ │ │ │ ├── shared-workflow.actions.ts
│ │ │ │ └── twilio.actions.ts
│ │ │ ├── api/
│ │ │ │ ├── composio/
│ │ │ │ │ └── webhook/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── copilot-stream-response/
│ │ │ │ │ └── [streamId]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── generated-images/
│ │ │ │ │ └── [id]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── me/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── stream-response/
│ │ │ │ │ └── [streamId]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── tmp-images/
│ │ │ │ │ └── [id]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── twilio/
│ │ │ │ │ ├── inbound_call/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ ├── turn/
│ │ │ │ │ │ └── [callSid]/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── uploads/
│ │ │ │ │ └── [fileId]/
│ │ │ │ │ └── route.ts
│ │ │ │ ├── v1/
│ │ │ │ │ └── [projectId]/
│ │ │ │ │ └── chat/
│ │ │ │ │ └── route.ts
│ │ │ │ └── widget/
│ │ │ │ └── v1/
│ │ │ │ ├── chats/
│ │ │ │ │ ├── [chatId]/
│ │ │ │ │ │ ├── close/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── messages/
│ │ │ │ │ │ │ └── route.ts
│ │ │ │ │ │ ├── route.ts
│ │ │ │ │ │ └── turn/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── route.ts
│ │ │ │ ├── session/
│ │ │ │ │ ├── guest/
│ │ │ │ │ │ └── route.ts
│ │ │ │ │ └── user/
│ │ │ │ │ └── route.ts
│ │ │ │ └── utils.ts
│ │ │ ├── app.tsx
│ │ │ ├── billing/
│ │ │ │ ├── app.tsx
│ │ │ │ ├── callback/
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── browserconfig.xml
│ │ │ ├── components/
│ │ │ │ └── ui/
│ │ │ │ └── textarea-with-send.tsx
│ │ │ ├── composio/
│ │ │ │ └── oauth2/
│ │ │ │ └── callback/
│ │ │ │ └── page.tsx
│ │ │ ├── globals.css
│ │ │ ├── hero.ts
│ │ │ ├── layout.tsx
│ │ │ ├── lib/
│ │ │ │ ├── assistant_templates_seed.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── auth0.ts
│ │ │ │ ├── billing.ts
│ │ │ │ ├── client_utils.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── atmentions.ts
│ │ │ │ │ ├── datasource-icon.tsx
│ │ │ │ │ ├── dropdown.tsx
│ │ │ │ │ ├── form-section.tsx
│ │ │ │ │ ├── form-status-button-old.tsx
│ │ │ │ │ ├── form-status-button.tsx
│ │ │ │ │ ├── icons.tsx
│ │ │ │ │ ├── input-field.tsx
│ │ │ │ │ ├── label.tsx
│ │ │ │ │ ├── markdown-content.tsx
│ │ │ │ │ ├── mentions-editor.css
│ │ │ │ │ ├── mentions_editor.tsx
│ │ │ │ │ ├── menu-item.tsx
│ │ │ │ │ ├── message-display.tsx
│ │ │ │ │ ├── page-section.tsx
│ │ │ │ │ ├── pagination.tsx
│ │ │ │ │ ├── reason-badge.tsx
│ │ │ │ │ ├── structured-list.tsx
│ │ │ │ │ ├── structured-panel.tsx
│ │ │ │ │ ├── typewriter.tsx
│ │ │ │ │ └── user_button.tsx
│ │ │ │ ├── default_tools.ts
│ │ │ │ ├── embedding.ts
│ │ │ │ ├── feature_flags.ts
│ │ │ │ ├── loadenv.ts
│ │ │ │ ├── mcp.ts
│ │ │ │ ├── mongodb.ts
│ │ │ │ ├── prebuilt-cards/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── customer-support.json
│ │ │ │ │ ├── eisenhower-email-organizer.json
│ │ │ │ │ ├── github-data-to-spreadsheet.json
│ │ │ │ │ ├── github-issue-to-slack.json
│ │ │ │ │ ├── github-pr-to-slack.json
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── interview-scheduler.json
│ │ │ │ │ ├── meeting-prep-assistant.json
│ │ │ │ │ ├── reddit-on-slack.json
│ │ │ │ │ ├── tweet-assistant.json
│ │ │ │ │ └── twitter-sentiment.json
│ │ │ │ ├── project_templates.ts
│ │ │ │ ├── qdrant.ts
│ │ │ │ ├── redis.ts
│ │ │ │ ├── types/
│ │ │ │ │ ├── api_types.ts
│ │ │ │ │ ├── billing_types.ts
│ │ │ │ │ ├── datasource_types.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── voice_types.ts
│ │ │ │ │ └── workflow_types.ts
│ │ │ │ ├── uploads_s3_client.ts
│ │ │ │ └── utils.ts
│ │ │ ├── loading.tsx
│ │ │ ├── new-chat-link.tsx
│ │ │ ├── onboarding/
│ │ │ │ ├── app.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── page.tsx
│ │ │ ├── projects/
│ │ │ │ ├── [projectId]/
│ │ │ │ │ ├── config/
│ │ │ │ │ │ ├── app.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── project.tsx
│ │ │ │ │ │ │ ├── shared-styles.ts
│ │ │ │ │ │ │ └── voice.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── conversations/
│ │ │ │ │ │ ├── [conversationId]/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── conversation-view.tsx
│ │ │ │ │ │ │ └── conversations-list.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── copilot/
│ │ │ │ │ │ ├── app.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── TriggerSetupModal.tsx
│ │ │ │ │ │ │ ├── actions.tsx
│ │ │ │ │ │ │ ├── messages.tsx
│ │ │ │ │ │ │ └── use-trigger-actions.ts
│ │ │ │ │ │ ├── example.md
│ │ │ │ │ │ ├── use-copilot.tsx
│ │ │ │ │ │ └── use-parsed-blocks.tsx
│ │ │ │ │ ├── entities/
│ │ │ │ │ │ ├── AgentGraphVisualizer.tsx
│ │ │ │ │ │ ├── agent_config.tsx
│ │ │ │ │ │ ├── datasource_config.tsx
│ │ │ │ │ │ ├── pipeline_config.tsx
│ │ │ │ │ │ ├── prompt_config.tsx
│ │ │ │ │ │ └── tool_config.tsx
│ │ │ │ │ ├── jobs/
│ │ │ │ │ │ ├── [jobId]/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── job-view.tsx
│ │ │ │ │ │ │ └── jobs-list.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── layout.tsx
│ │ │ │ │ ├── manage-triggers/
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── composio-trigger-deployment-view.tsx
│ │ │ │ │ │ │ ├── create-recurring-job-rule-form.tsx
│ │ │ │ │ │ │ ├── job-rules-tabs.tsx
│ │ │ │ │ │ │ ├── recurring-job-rule-view.tsx
│ │ │ │ │ │ │ ├── recurring-job-rules-list.tsx
│ │ │ │ │ │ │ └── triggers-tab.tsx
│ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ ├── recurring/
│ │ │ │ │ │ │ ├── [ruleId]/
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ └── new/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ ├── scheduled/
│ │ │ │ │ │ │ ├── [ruleId]/
│ │ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── create-scheduled-job-rule-form.tsx
│ │ │ │ │ │ │ │ ├── scheduled-job-rule-view.tsx
│ │ │ │ │ │ │ │ └── scheduled-job-rules-list.tsx
│ │ │ │ │ │ │ └── new/
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ └── triggers/
│ │ │ │ │ │ └── [deploymentId]/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── playground/
│ │ │ │ │ │ ├── app.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── chat.tsx
│ │ │ │ │ │ │ ├── feedback-modal.tsx
│ │ │ │ │ │ │ ├── messages.tsx
│ │ │ │ │ │ │ └── profile-context-box.tsx
│ │ │ │ │ │ └── copilot-prompts.ts
│ │ │ │ │ ├── sources/
│ │ │ │ │ │ ├── [sourceId]/
│ │ │ │ │ │ │ ├── page.tsx
│ │ │ │ │ │ │ └── source-page.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ │ ├── files-source.tsx
│ │ │ │ │ │ │ ├── scrape-source.tsx
│ │ │ │ │ │ │ ├── section.tsx
│ │ │ │ │ │ │ ├── self-updating-source-status.tsx
│ │ │ │ │ │ │ ├── shared.tsx
│ │ │ │ │ │ │ ├── source-status.tsx
│ │ │ │ │ │ │ ├── sources-list.tsx
│ │ │ │ │ │ │ ├── text-source.tsx
│ │ │ │ │ │ │ ├── toggle-source.tsx
│ │ │ │ │ │ │ └── web-recrawl.tsx
│ │ │ │ │ │ ├── new/
│ │ │ │ │ │ │ ├── form.tsx
│ │ │ │ │ │ │ └── page.tsx
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ ├── tools/
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── AddWebhookTool.tsx
│ │ │ │ │ │ │ ├── ComposioToolsPanel.tsx
│ │ │ │ │ │ │ ├── CustomMcpServer.tsx
│ │ │ │ │ │ │ ├── MCPServersCommon.tsx
│ │ │ │ │ │ │ ├── McpToolsPanel.tsx
│ │ │ │ │ │ │ ├── SelectComposioToolkit.tsx
│ │ │ │ │ │ │ ├── ServerCard.tsx
│ │ │ │ │ │ │ ├── ToolkitAuthModal.tsx
│ │ │ │ │ │ │ ├── ToolkitCard.tsx
│ │ │ │ │ │ │ ├── ToolsConfig.tsx
│ │ │ │ │ │ │ └── WebhookConfig.tsx
│ │ │ │ │ │ └── oauth/
│ │ │ │ │ │ └── callback/
│ │ │ │ │ │ └── page.tsx
│ │ │ │ │ └── workflow/
│ │ │ │ │ ├── app.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ComposioTriggerTypesPanel.tsx
│ │ │ │ │ │ ├── DataSourcesModal.tsx
│ │ │ │ │ │ ├── ToolsModal.tsx
│ │ │ │ │ │ ├── TopBar.tsx
│ │ │ │ │ │ └── TriggerConfigForm.tsx
│ │ │ │ │ ├── config_list.tsx
│ │ │ │ │ ├── entity_list.tsx
│ │ │ │ │ ├── error.tsx
│ │ │ │ │ ├── loading.tsx
│ │ │ │ │ ├── page.tsx
│ │ │ │ │ ├── pane.tsx
│ │ │ │ │ ├── preview-modal.tsx
│ │ │ │ │ ├── trigger-transform.ts
│ │ │ │ │ └── workflow_editor.tsx
│ │ │ │ ├── app.tsx
│ │ │ │ ├── components/
│ │ │ │ │ ├── build-assistant-section.tsx
│ │ │ │ │ ├── create-project.tsx
│ │ │ │ │ ├── custom-prompt-card.tsx
│ │ │ │ │ ├── project-list.tsx
│ │ │ │ │ ├── search-input.tsx
│ │ │ │ │ ├── search-projects.tsx
│ │ │ │ │ ├── submit-button.tsx
│ │ │ │ │ └── templates-section.tsx
│ │ │ │ ├── layout/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── app-layout.tsx
│ │ │ │ │ │ ├── menu-item.tsx
│ │ │ │ │ │ └── sidebar.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── menu.tsx
│ │ │ │ │ └── nav.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── lib/
│ │ │ │ │ └── project-creation-utils.ts
│ │ │ │ └── page.tsx
│ │ │ ├── providers/
│ │ │ │ ├── help-modal-provider.tsx
│ │ │ │ └── theme-provider.tsx
│ │ │ ├── providers.tsx
│ │ │ ├── scripts/
│ │ │ │ ├── delete_qdrant.ts
│ │ │ │ ├── job-rules.worker.ts
│ │ │ │ ├── jobs-worker.ts
│ │ │ │ ├── mongodb-drop-indexes.ts
│ │ │ │ ├── mongodb-ensure-indexes.ts
│ │ │ │ ├── rag-worker.ts
│ │ │ │ └── setup_qdrant.ts
│ │ │ ├── site.webmanifest
│ │ │ └── styles/
│ │ │ ├── design-tokens.ts
│ │ │ ├── pane-effects.ts
│ │ │ └── quill-mentions.css
│ │ ├── components/
│ │ │ ├── common/
│ │ │ │ ├── AssistantCard.tsx
│ │ │ │ ├── AssistantSection.tsx
│ │ │ │ ├── UnifiedTemplatesSection.tsx
│ │ │ │ ├── billing-upgrade-modal.tsx
│ │ │ │ ├── compose-box-copilot.tsx
│ │ │ │ ├── compose-box-playground.tsx
│ │ │ │ ├── compose-box.tsx
│ │ │ │ ├── copy-as-json-button.tsx
│ │ │ │ ├── copy-button.tsx
│ │ │ │ ├── help-modal.tsx
│ │ │ │ ├── panel-common.tsx
│ │ │ │ ├── product-tour.tsx
│ │ │ │ ├── project-wide-change-confirmation-modal.tsx
│ │ │ │ ├── section-card.tsx
│ │ │ │ └── tool-param-card.tsx
│ │ │ └── ui/
│ │ │ ├── button.tsx
│ │ │ ├── dropdown.tsx
│ │ │ ├── horizontal-divider.tsx
│ │ │ ├── input.tsx
│ │ │ ├── modal.tsx
│ │ │ ├── page-header.tsx
│ │ │ ├── page-heading.tsx
│ │ │ ├── picture-img.tsx
│ │ │ ├── progress-bar.tsx
│ │ │ ├── resizable.tsx
│ │ │ ├── search-bar.tsx
│ │ │ ├── section-heading.tsx
│ │ │ ├── slide-panel.tsx
│ │ │ ├── switch.tsx
│ │ │ ├── tabs.tsx
│ │ │ └── textarea.tsx
│ │ ├── components.json
│ │ ├── di/
│ │ │ └── container.ts
│ │ ├── hooks/
│ │ │ └── use-click-away.ts
│ │ ├── instrumentation-client.ts
│ │ ├── lib/
│ │ │ ├── utils/
│ │ │ │ └── date.ts
│ │ │ └── utils.ts
│ │ ├── middleware.ts
│ │ ├── next.config.mjs
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── scripts.Dockerfile
│ │ ├── src/
│ │ │ ├── application/
│ │ │ │ ├── lib/
│ │ │ │ │ ├── agents-runtime/
│ │ │ │ │ │ ├── agent-handoffs.ts
│ │ │ │ │ │ ├── agent-tools.ts
│ │ │ │ │ │ ├── agent_instructions.ts
│ │ │ │ │ │ ├── agents.ts
│ │ │ │ │ │ └── pipeline-state-manager.ts
│ │ │ │ │ ├── composio/
│ │ │ │ │ │ ├── composio.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── copilot/
│ │ │ │ │ │ ├── copilot.ts
│ │ │ │ │ │ ├── copilot_edit_agent.ts
│ │ │ │ │ │ ├── copilot_multi_agent.ts
│ │ │ │ │ │ ├── copilot_multi_agent_build.ts
│ │ │ │ │ │ ├── current_workflow.ts
│ │ │ │ │ │ └── example_multi_agent_1.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── is-valid-cron-expression.ts
│ │ │ │ │ └── time-to-next-minute.ts
│ │ │ │ ├── policies/
│ │ │ │ │ ├── project-action-authorization.policy.ts
│ │ │ │ │ └── usage-quota.policy.interface.ts
│ │ │ │ ├── repositories/
│ │ │ │ │ ├── api-keys.repository.interface.ts
│ │ │ │ │ ├── composio-trigger-deployments.repository.interface.ts
│ │ │ │ │ ├── conversations.repository.interface.ts
│ │ │ │ │ ├── data-source-docs.repository.interface.ts
│ │ │ │ │ ├── data-sources.repository.interface.ts
│ │ │ │ │ ├── jobs.repository.interface.ts
│ │ │ │ │ ├── project-members.repository.interface.ts
│ │ │ │ │ ├── projects.repository.interface.ts
│ │ │ │ │ ├── recurring-job-rules.repository.interface.ts
│ │ │ │ │ ├── scheduled-job-rules.repository.interface.ts
│ │ │ │ │ └── users.repository.interface.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── cache.service.interface.ts
│ │ │ │ │ ├── pub-sub.service.interface.ts
│ │ │ │ │ ├── temp-binary-cache.ts
│ │ │ │ │ └── uploads-storage.service.interface.ts
│ │ │ │ ├── use-cases/
│ │ │ │ │ ├── api-keys/
│ │ │ │ │ │ ├── create-api-key.use-case.ts
│ │ │ │ │ │ ├── delete-api-key.use-case.ts
│ │ │ │ │ │ └── list-api-keys.use-case.ts
│ │ │ │ │ ├── composio/
│ │ │ │ │ │ └── webhook/
│ │ │ │ │ │ └── handle-composio-webhook-request.use-case.ts
│ │ │ │ │ ├── composio-trigger-deployments/
│ │ │ │ │ │ ├── create-composio-trigger-deployment.use-case.ts
│ │ │ │ │ │ ├── delete-composio-trigger-deployment.use-case.ts
│ │ │ │ │ │ ├── fetch-composio-trigger-deployment.use-case.ts
│ │ │ │ │ │ ├── list-composio-trigger-deployments.use-case.ts
│ │ │ │ │ │ └── list-composio-trigger-types.use-case.ts
│ │ │ │ │ ├── conversations/
│ │ │ │ │ │ ├── create-cached-turn.use-case.ts
│ │ │ │ │ │ ├── create-conversation.use-case.ts
│ │ │ │ │ │ ├── fetch-cached-turn.use-case.ts
│ │ │ │ │ │ ├── fetch-conversation.use-case.ts
│ │ │ │ │ │ ├── list-conversations.use-case.ts
│ │ │ │ │ │ └── run-conversation-turn.use-case.ts
│ │ │ │ │ ├── copilot/
│ │ │ │ │ │ ├── create-copilot-cached-turn.use-case.ts
│ │ │ │ │ │ └── run-copilot-cached-turn.use-case.ts
│ │ │ │ │ ├── data-sources/
│ │ │ │ │ │ ├── add-docs-to-data-source.use-case.ts
│ │ │ │ │ │ ├── create-data-source.use-case.ts
│ │ │ │ │ │ ├── delete-data-source.use-case.ts
│ │ │ │ │ │ ├── delete-doc-from-data-source.use-case.ts
│ │ │ │ │ │ ├── fetch-data-source.use-case.ts
│ │ │ │ │ │ ├── get-download-url-for-file.use-case.ts
│ │ │ │ │ │ ├── get-upload-urls-for-files.use-case.ts
│ │ │ │ │ │ ├── list-data-sources.use-case.ts
│ │ │ │ │ │ ├── list-docs-in-data-source.use-case.ts
│ │ │ │ │ │ ├── recrawl-web-data-source.use-case.ts
│ │ │ │ │ │ ├── toggle-data-source.use-case.ts
│ │ │ │ │ │ └── update-data-source.use-case.ts
│ │ │ │ │ ├── jobs/
│ │ │ │ │ │ ├── fetch-job.use-case.ts
│ │ │ │ │ │ └── list-jobs.use-case.ts
│ │ │ │ │ ├── projects/
│ │ │ │ │ │ ├── add-custom-mcp-server.use-case.ts
│ │ │ │ │ │ ├── create-composio-managed-connected-account.use-case.ts
│ │ │ │ │ │ ├── create-custom-connected-account.use-case.ts
│ │ │ │ │ │ ├── create-project.use-case.ts
│ │ │ │ │ │ ├── delete-composio-connected-account.use-case.ts
│ │ │ │ │ │ ├── delete-project.use-case.ts
│ │ │ │ │ │ ├── fetch-project.use-case.ts
│ │ │ │ │ │ ├── get-composio-toolkit.use-case.ts
│ │ │ │ │ │ ├── list-composio-toolkits.use-case.ts
│ │ │ │ │ │ ├── list-composio-tools.use-case.ts
│ │ │ │ │ │ ├── list-projects.use-case.ts
│ │ │ │ │ │ ├── remove-custom-mcp-server.use-case.ts
│ │ │ │ │ │ ├── revert-to-live-workflow.use-case.ts
│ │ │ │ │ │ ├── rotate-secret.use-case.ts
│ │ │ │ │ │ ├── sync-connected-account.use-case.ts
│ │ │ │ │ │ ├── update-draft-workflow.use-case.ts
│ │ │ │ │ │ ├── update-live-workflow.use-case.ts
│ │ │ │ │ │ ├── update-project-name.use-case.ts
│ │ │ │ │ │ └── update-webhook-url.use-case.ts
│ │ │ │ │ ├── recurring-job-rules/
│ │ │ │ │ │ ├── create-recurring-job-rule.use-case.ts
│ │ │ │ │ │ ├── delete-recurring-job-rule.use-case.ts
│ │ │ │ │ │ ├── fetch-recurring-job-rule.use-case.ts
│ │ │ │ │ │ ├── list-recurring-job-rules.use-case.ts
│ │ │ │ │ │ ├── toggle-recurring-job-rule.use-case.ts
│ │ │ │ │ │ └── update-recurring-job-rule.use-case.ts
│ │ │ │ │ └── scheduled-job-rules/
│ │ │ │ │ ├── create-scheduled-job-rule.use-case.ts
│ │ │ │ │ ├── delete-scheduled-job-rule.use-case.ts
│ │ │ │ │ ├── fetch-scheduled-job-rule.use-case.ts
│ │ │ │ │ ├── list-scheduled-job-rules.use-case.ts
│ │ │ │ │ └── update-scheduled-job-rule.use-case.ts
│ │ │ │ └── workers/
│ │ │ │ ├── job-rules.worker.ts
│ │ │ │ └── jobs.worker.ts
│ │ │ ├── entities/
│ │ │ │ ├── common/
│ │ │ │ │ └── paginated-list.ts
│ │ │ │ ├── errors/
│ │ │ │ │ ├── common.ts
│ │ │ │ │ └── job-errors.ts
│ │ │ │ └── models/
│ │ │ │ ├── api-key.ts
│ │ │ │ ├── assistant-template.ts
│ │ │ │ ├── composio-trigger-deployment.ts
│ │ │ │ ├── composio-trigger-type.ts
│ │ │ │ ├── conversation.ts
│ │ │ │ ├── copilot.ts
│ │ │ │ ├── data-source-doc.ts
│ │ │ │ ├── data-source.ts
│ │ │ │ ├── job.ts
│ │ │ │ ├── project-member.ts
│ │ │ │ ├── project.ts
│ │ │ │ ├── recurring-job-rule.ts
│ │ │ │ ├── scheduled-job-rule.ts
│ │ │ │ ├── turn.ts
│ │ │ │ └── user.ts
│ │ │ ├── infrastructure/
│ │ │ │ ├── mongodb/
│ │ │ │ │ ├── drop-indexes.ts
│ │ │ │ │ └── ensure-indexes.ts
│ │ │ │ ├── policies/
│ │ │ │ │ └── redis.usage-quota.policy.ts
│ │ │ │ ├── repositories/
│ │ │ │ │ ├── mongodb.api-keys.indexes.ts
│ │ │ │ │ ├── mongodb.api-keys.repository.ts
│ │ │ │ │ ├── mongodb.assistant-templates.repository.ts
│ │ │ │ │ ├── mongodb.community-assistants.indexes.ts
│ │ │ │ │ ├── mongodb.composio-trigger-deployments.indexes.ts
│ │ │ │ │ ├── mongodb.composio-trigger-deployments.repository.ts
│ │ │ │ │ ├── mongodb.conversations.indexes.ts
│ │ │ │ │ ├── mongodb.conversations.repository.ts
│ │ │ │ │ ├── mongodb.data-source-docs.indexes.ts
│ │ │ │ │ ├── mongodb.data-source-docs.repository.ts
│ │ │ │ │ ├── mongodb.data-sources.indexes.ts
│ │ │ │ │ ├── mongodb.data-sources.repository.ts
│ │ │ │ │ ├── mongodb.jobs.indexes.ts
│ │ │ │ │ ├── mongodb.jobs.repository.ts
│ │ │ │ │ ├── mongodb.project-members.indexes.ts
│ │ │ │ │ ├── mongodb.project-members.repository.ts
│ │ │ │ │ ├── mongodb.projects.indexes.ts
│ │ │ │ │ ├── mongodb.projects.repository.ts
│ │ │ │ │ ├── mongodb.recurring-job-rules.indexes.ts
│ │ │ │ │ ├── mongodb.recurring-job-rules.repository.ts
│ │ │ │ │ ├── mongodb.scheduled-job-rules.indexes.ts
│ │ │ │ │ ├── mongodb.scheduled-job-rules.repository.ts
│ │ │ │ │ ├── mongodb.shared-workflows.indexes.ts
│ │ │ │ │ ├── mongodb.users.indexes.ts
│ │ │ │ │ └── mongodb.users.repository.ts
│ │ │ │ └── services/
│ │ │ │ ├── local.uploads-storage.service.ts
│ │ │ │ ├── redis.cache.service.ts
│ │ │ │ ├── redis.pub-sub.service.ts
│ │ │ │ └── s3.uploads-storage.service.ts
│ │ │ └── interface-adapters/
│ │ │ └── controllers/
│ │ │ ├── api-keys/
│ │ │ │ ├── create-api-key.controller.ts
│ │ │ │ ├── delete-api-key.controller.ts
│ │ │ │ └── list-api-keys.controller.ts
│ │ │ ├── composio/
│ │ │ │ └── webhook/
│ │ │ │ └── handle-composio-webhook-request.controller.ts
│ │ │ ├── composio-trigger-deployments/
│ │ │ │ ├── create-composio-trigger-deployment.controller.ts
│ │ │ │ ├── delete-composio-trigger-deployment.controller.ts
│ │ │ │ ├── fetch-composio-trigger-deployment.controller.ts
│ │ │ │ ├── list-composio-trigger-deployments.controller.ts
│ │ │ │ └── list-composio-trigger-types.controller.ts
│ │ │ ├── conversations/
│ │ │ │ ├── create-cached-turn.controller.ts
│ │ │ │ ├── create-playground-conversation.controller.ts
│ │ │ │ ├── fetch-conversation.controller.ts
│ │ │ │ ├── list-conversations.controller.ts
│ │ │ │ ├── run-cached-turn.controller.ts
│ │ │ │ └── run-turn.controller.ts
│ │ │ ├── copilot/
│ │ │ │ ├── create-copilot-cached-turn.controller.ts
│ │ │ │ └── run-copilot-cached-turn.controller.ts
│ │ │ ├── data-sources/
│ │ │ │ ├── add-docs-to-data-source.controller.ts
│ │ │ │ ├── create-data-source.controller.ts
│ │ │ │ ├── delete-data-source.controller.ts
│ │ │ │ ├── delete-doc-from-data-source.controller.ts
│ │ │ │ ├── fetch-data-source.controller.ts
│ │ │ │ ├── get-download-url-for-file.controller.ts
│ │ │ │ ├── get-upload-urls-for-files.controller.ts
│ │ │ │ ├── list-data-sources.controller.ts
│ │ │ │ ├── list-docs-in-data-source.controller.ts
│ │ │ │ ├── recrawl-web-data-source.controller.ts
│ │ │ │ ├── toggle-data-source.controller.ts
│ │ │ │ └── update-data-source.controller.ts
│ │ │ ├── jobs/
│ │ │ │ ├── fetch-job.controller.ts
│ │ │ │ └── list-jobs.controller.ts
│ │ │ ├── projects/
│ │ │ │ ├── add-custom-mcp-server.controller.ts
│ │ │ │ ├── create-composio-managed-connected-account.controller.ts
│ │ │ │ ├── create-custom-connected-account.controller.ts
│ │ │ │ ├── create-project.controller.ts
│ │ │ │ ├── delete-composio-connected-account.controller.ts
│ │ │ │ ├── delete-project.controller.ts
│ │ │ │ ├── fetch-project.controller.ts
│ │ │ │ ├── get-composio-toolkit.controller.ts
│ │ │ │ ├── list-composio-toolkits.controller.ts
│ │ │ │ ├── list-composio-tools.controller.ts
│ │ │ │ ├── list-projects.controller.ts
│ │ │ │ ├── remove-custom-mcp-server.controller.ts
│ │ │ │ ├── revert-to-live-workflow.controller.ts
│ │ │ │ ├── rotate-secret.controller.ts
│ │ │ │ ├── sync-connected-account.controller.ts
│ │ │ │ ├── update-draft-workflow.controller.ts
│ │ │ │ ├── update-live-workflow.controller.ts
│ │ │ │ ├── update-project-name.controller.ts
│ │ │ │ └── update-webhook-url.controller.ts
│ │ │ ├── recurring-job-rules/
│ │ │ │ ├── create-recurring-job-rule.controller.ts
│ │ │ │ ├── delete-recurring-job-rule.controller.ts
│ │ │ │ ├── fetch-recurring-job-rule.controller.ts
│ │ │ │ ├── list-recurring-job-rules.controller.ts
│ │ │ │ ├── toggle-recurring-job-rule.controller.ts
│ │ │ │ └── update-recurring-job-rule.controller.ts
│ │ │ └── scheduled-job-rules/
│ │ │ ├── create-scheduled-job-rule.controller.ts
│ │ │ ├── delete-scheduled-job-rule.controller.ts
│ │ │ ├── fetch-scheduled-job-rule.controller.ts
│ │ │ ├── list-scheduled-job-rules.controller.ts
│ │ │ └── update-scheduled-job-rule.controller.ts
│ │ └── tsconfig.json
│ ├── rowboatx/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── app/
│ │ │ ├── globals.css
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ ├── components/
│ │ │ ├── ai-elements/
│ │ │ │ ├── artifact.tsx
│ │ │ │ ├── canvas.tsx
│ │ │ │ ├── chain-of-thought.tsx
│ │ │ │ ├── checkpoint.tsx
│ │ │ │ ├── code-block.tsx
│ │ │ │ ├── confirmation.tsx
│ │ │ │ ├── connection.tsx
│ │ │ │ ├── context.tsx
│ │ │ │ ├── controls.tsx
│ │ │ │ ├── conversation.tsx
│ │ │ │ ├── edge.tsx
│ │ │ │ ├── image.tsx
│ │ │ │ ├── inline-citation.tsx
│ │ │ │ ├── loader.tsx
│ │ │ │ ├── message.tsx
│ │ │ │ ├── model-selector.tsx
│ │ │ │ ├── node.tsx
│ │ │ │ ├── open-in-chat.tsx
│ │ │ │ ├── panel.tsx
│ │ │ │ ├── plan.tsx
│ │ │ │ ├── prompt-input.tsx
│ │ │ │ ├── queue.tsx
│ │ │ │ ├── reasoning.tsx
│ │ │ │ ├── shimmer.tsx
│ │ │ │ ├── sources.tsx
│ │ │ │ ├── suggestion.tsx
│ │ │ │ ├── task.tsx
│ │ │ │ ├── tool.tsx
│ │ │ │ ├── toolbar.tsx
│ │ │ │ └── web-preview.tsx
│ │ │ ├── app-sidebar.tsx
│ │ │ ├── json-editor.css
│ │ │ ├── json-editor.tsx
│ │ │ ├── markdown-viewer.css
│ │ │ ├── markdown-viewer.tsx
│ │ │ ├── nav-main.tsx
│ │ │ ├── nav-projects.tsx
│ │ │ ├── nav-user.tsx
│ │ │ ├── team-switcher.tsx
│ │ │ ├── tiptap-markdown-editor.css
│ │ │ ├── tiptap-markdown-editor.tsx
│ │ │ └── ui/
│ │ │ ├── alert.tsx
│ │ │ ├── avatar.tsx
│ │ │ ├── badge.tsx
│ │ │ ├── breadcrumb.tsx
│ │ │ ├── button-group.tsx
│ │ │ ├── button.tsx
│ │ │ ├── card.tsx
│ │ │ ├── carousel.tsx
│ │ │ ├── collapsible.tsx
│ │ │ ├── command.tsx
│ │ │ ├── dialog.tsx
│ │ │ ├── dropdown-menu.tsx
│ │ │ ├── hover-card.tsx
│ │ │ ├── input-group.tsx
│ │ │ ├── input.tsx
│ │ │ ├── progress.tsx
│ │ │ ├── scroll-area.tsx
│ │ │ ├── select.tsx
│ │ │ ├── separator.tsx
│ │ │ ├── sheet.tsx
│ │ │ ├── sidebar.tsx
│ │ │ ├── skeleton.tsx
│ │ │ ├── textarea.tsx
│ │ │ └── tooltip.tsx
│ │ ├── components.json
│ │ ├── eslint.config.mjs
│ │ ├── global.d.ts
│ │ ├── hooks/
│ │ │ └── use-mobile.ts
│ │ ├── lib/
│ │ │ └── utils.ts
│ │ ├── next.config.ts
│ │ ├── package.json
│ │ ├── postcss.config.mjs
│ │ ├── tsconfig.json
│ │ └── types/
│ │ └── turndown.d.ts
│ └── x/
│ ├── .gitignore
│ ├── apps/
│ │ ├── main/
│ │ │ ├── .gitignore
│ │ │ ├── bundle.mjs
│ │ │ ├── forge.config.cjs
│ │ │ ├── icons/
│ │ │ │ └── icon.icns
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── auth-server.ts
│ │ │ │ ├── composio-handler.ts
│ │ │ │ ├── ipc.ts
│ │ │ │ ├── main.ts
│ │ │ │ ├── oauth-handler.ts
│ │ │ │ └── test-agent.ts
│ │ │ └── tsconfig.json
│ │ ├── preload/
│ │ │ ├── .gitignore
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ └── preload.ts
│ │ │ └── tsconfig.json
│ │ └── renderer/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── components.json
│ │ ├── eslint.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── App.css
│ │ │ ├── App.tsx
│ │ │ ├── components/
│ │ │ │ ├── ai-elements/
│ │ │ │ │ ├── ask-human-request.tsx
│ │ │ │ │ ├── context.tsx
│ │ │ │ │ ├── conversation.tsx
│ │ │ │ │ ├── file-path-card.tsx
│ │ │ │ │ ├── markdown-code-override.tsx
│ │ │ │ │ ├── message.tsx
│ │ │ │ │ ├── permission-request.tsx
│ │ │ │ │ ├── prompt-input.tsx
│ │ │ │ │ ├── reasoning.tsx
│ │ │ │ │ ├── shimmer.tsx
│ │ │ │ │ ├── suggestions.tsx
│ │ │ │ │ ├── tool.tsx
│ │ │ │ │ └── web-search-result.tsx
│ │ │ │ ├── background-task-detail.tsx
│ │ │ │ ├── chat-button.tsx
│ │ │ │ ├── chat-input-with-mentions.tsx
│ │ │ │ ├── chat-message-attachments.tsx
│ │ │ │ ├── chat-sidebar.tsx
│ │ │ │ ├── composio-api-key-modal.tsx
│ │ │ │ ├── connectors-popover.tsx
│ │ │ │ ├── editor-toolbar.tsx
│ │ │ │ ├── google-client-id-modal.tsx
│ │ │ │ ├── graph-view.tsx
│ │ │ │ ├── help-popover.tsx
│ │ │ │ ├── markdown-editor.tsx
│ │ │ │ ├── mention-popover.tsx
│ │ │ │ ├── onboarding-modal.tsx
│ │ │ │ ├── search-dialog.tsx
│ │ │ │ ├── settings-dialog.tsx
│ │ │ │ ├── sidebar-content.tsx
│ │ │ │ ├── tab-bar.tsx
│ │ │ │ ├── ui/
│ │ │ │ │ ├── alert-dialog.tsx
│ │ │ │ │ ├── badge.tsx
│ │ │ │ │ ├── button-group.tsx
│ │ │ │ │ ├── button.tsx
│ │ │ │ │ ├── collapsible.tsx
│ │ │ │ │ ├── command.tsx
│ │ │ │ │ ├── context-menu.tsx
│ │ │ │ │ ├── dialog.tsx
│ │ │ │ │ ├── dropdown-menu.tsx
│ │ │ │ │ ├── hover-card.tsx
│ │ │ │ │ ├── input-group.tsx
│ │ │ │ │ ├── input.tsx
│ │ │ │ │ ├── popover.tsx
│ │ │ │ │ ├── progress.tsx
│ │ │ │ │ ├── select.tsx
│ │ │ │ │ ├── separator.tsx
│ │ │ │ │ ├── sheet.tsx
│ │ │ │ │ ├── sidebar.tsx
│ │ │ │ │ ├── skeleton.tsx
│ │ │ │ │ ├── sonner.tsx
│ │ │ │ │ ├── switch.tsx
│ │ │ │ │ ├── textarea.tsx
│ │ │ │ │ └── tooltip.tsx
│ │ │ │ └── version-history-panel.tsx
│ │ │ ├── contexts/
│ │ │ │ ├── file-card-context.tsx
│ │ │ │ ├── sidebar-context.tsx
│ │ │ │ └── theme-context.tsx
│ │ │ ├── extensions/
│ │ │ │ ├── image-upload.tsx
│ │ │ │ └── wiki-link.ts
│ │ │ ├── global.d.ts
│ │ │ ├── hooks/
│ │ │ │ ├── use-debounce.ts
│ │ │ │ ├── use-mention-detection.ts
│ │ │ │ ├── use-mobile.ts
│ │ │ │ └── useOAuth.ts
│ │ │ ├── index.css
│ │ │ ├── lib/
│ │ │ │ ├── attachment-presentation.ts
│ │ │ │ ├── chat-conversation.ts
│ │ │ │ ├── file-utils.ts
│ │ │ │ ├── google-client-id-store.ts
│ │ │ │ ├── mention-files.ts
│ │ │ │ ├── mention-highlights.ts
│ │ │ │ ├── textarea-caret.ts
│ │ │ │ ├── toast.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── wiki-links.ts
│ │ │ ├── main.tsx
│ │ │ └── styles/
│ │ │ └── editor.css
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ ├── eslint.config.mts
│ ├── package.json
│ ├── packages/
│ │ ├── core/
│ │ │ ├── .gitignore
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── agent-schedule/
│ │ │ │ │ ├── repo.ts
│ │ │ │ │ ├── runner.ts
│ │ │ │ │ └── state-repo.ts
│ │ │ │ ├── agents/
│ │ │ │ │ ├── repo.ts
│ │ │ │ │ └── runtime.ts
│ │ │ │ ├── application/
│ │ │ │ │ ├── assistant/
│ │ │ │ │ │ ├── agent.ts
│ │ │ │ │ │ ├── instructions.ts
│ │ │ │ │ │ ├── runtime-context.ts
│ │ │ │ │ │ └── skills/
│ │ │ │ │ │ ├── background-agents/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── builtin-tools/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── create-presentations/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── deletion-guardrails/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── doc-collab/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── draft-emails/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── mcp-integration/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── meeting-prep/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── organize-files/
│ │ │ │ │ │ │ └── skill.ts
│ │ │ │ │ │ ├── slack/
│ │ │ │ │ │ │ ├── skill.ts
│ │ │ │ │ │ │ └── tool-catalog.ts
│ │ │ │ │ │ └── web-search/
│ │ │ │ │ │ └── skill.ts
│ │ │ │ │ └── lib/
│ │ │ │ │ ├── builtin-tools.ts
│ │ │ │ │ ├── bus.ts
│ │ │ │ │ ├── command-executor.ts
│ │ │ │ │ ├── exec-tool.ts
│ │ │ │ │ ├── id-gen.ts
│ │ │ │ │ └── message-queue.ts
│ │ │ │ ├── auth/
│ │ │ │ │ ├── client-repo.ts
│ │ │ │ │ ├── oauth-client.ts
│ │ │ │ │ ├── provider-client-id.ts
│ │ │ │ │ ├── providers.ts
│ │ │ │ │ ├── repo.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── composio/
│ │ │ │ │ ├── client.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── repo.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── config/
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── initConfigs.ts
│ │ │ │ │ ├── note_creation_config.ts
│ │ │ │ │ ├── security.ts
│ │ │ │ │ └── strictness_analyzer.ts
│ │ │ │ ├── di/
│ │ │ │ │ └── container.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── knowledge/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── build_graph.ts
│ │ │ │ │ ├── fireflies-client-factory.ts
│ │ │ │ │ ├── google-client-factory.ts
│ │ │ │ │ ├── granola/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── repo.ts
│ │ │ │ │ │ ├── sync.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── graph_state.ts
│ │ │ │ │ ├── knowledge_index.ts
│ │ │ │ │ ├── limit_event_items.ts
│ │ │ │ │ ├── note_creation_high.ts
│ │ │ │ │ ├── note_creation_low.ts
│ │ │ │ │ ├── note_creation_medium.ts
│ │ │ │ │ ├── sync_calendar.ts
│ │ │ │ │ ├── sync_fireflies.ts
│ │ │ │ │ ├── sync_gmail.ts
│ │ │ │ │ ├── version_history.ts
│ │ │ │ │ └── welcome.md
│ │ │ │ ├── mcp/
│ │ │ │ │ ├── mcp.ts
│ │ │ │ │ └── repo.ts
│ │ │ │ ├── models/
│ │ │ │ │ ├── models-dev.ts
│ │ │ │ │ ├── models.ts
│ │ │ │ │ └── repo.ts
│ │ │ │ ├── pre_built/
│ │ │ │ │ ├── config.ts
│ │ │ │ │ ├── email-draft.md
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── meeting-prep.md
│ │ │ │ │ ├── runner.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── runs/
│ │ │ │ │ ├── abort-registry.ts
│ │ │ │ │ ├── bus.ts
│ │ │ │ │ ├── lock.ts
│ │ │ │ │ ├── repo.ts
│ │ │ │ │ └── runs.ts
│ │ │ │ ├── search/
│ │ │ │ │ └── search.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── service_bus.ts
│ │ │ │ │ └── service_logger.ts
│ │ │ │ └── workspace/
│ │ │ │ ├── watcher.ts
│ │ │ │ ├── wiki-link-rewrite.ts
│ │ │ │ └── workspace.ts
│ │ │ └── tsconfig.json
│ │ └── shared/
│ │ ├── .gitignore
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── agent-schedule-state.ts
│ │ │ ├── agent-schedule.ts
│ │ │ ├── agent.ts
│ │ │ ├── example.ts
│ │ │ ├── index.ts
│ │ │ ├── ipc.ts
│ │ │ ├── llm-step-events.ts
│ │ │ ├── mcp.ts
│ │ │ ├── message.ts
│ │ │ ├── models.ts
│ │ │ ├── prefix-logger.ts
│ │ │ ├── runs.ts
│ │ │ ├── service-events.ts
│ │ │ └── workspace.ts
│ │ └── tsconfig.json
│ ├── pnpm-workspace.yaml
│ └── tsconfig.base.json
├── build-electron.sh
├── docker-compose.yml
├── google-setup.md
└── start.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
================================================
FILE: .github/workflows/electron-build.yml
================================================
name: Build Electron App
on:
release:
types: [published]
permissions:
contents: write # Required to upload release assets
jobs:
build-macos:
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'pnpm'
cache-dependency-path: 'apps/x/pnpm-lock.yaml'
- name: Extract version from tag
id: version
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Extracted version: ${VERSION}"
- name: Update package.json versions
run: |
node -e "
const fs = require('fs');
const version = '${{ steps.version.outputs.version }}';
// Update apps/x/package.json
const rootPackage = JSON.parse(fs.readFileSync('apps/x/package.json', 'utf8'));
rootPackage.version = version;
fs.writeFileSync('apps/x/package.json', JSON.stringify(rootPackage, null, 2) + '\n');
// Update apps/x/apps/main/package.json
const mainPackage = JSON.parse(fs.readFileSync('apps/x/apps/main/package.json', 'utf8'));
mainPackage.version = version;
fs.writeFileSync('apps/x/apps/main/package.json', JSON.stringify(mainPackage, null, 2) + '\n');
console.log('Updated version to:', version);
"
- name: Import Code Signing Certificate
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
run: |
# Create a temporary keychain
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
# Create keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Decode and import certificate
echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
security import $RUNNER_TEMP/certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
# Allow codesign to access the keychain
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
# Add keychain to search list
security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain
# Verify certificate was imported
security find-identity -v "$KEYCHAIN_PATH"
# Clean up certificate file
rm -f $RUNNER_TEMP/certificate.p12
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: apps/x
- name: Build electron app
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
VITE_PUBLIC_POSTHOG_KEY: ${{ secrets.VITE_PUBLIC_POSTHOG_KEY }}
VITE_PUBLIC_POSTHOG_HOST: ${{ secrets.VITE_PUBLIC_POSTHOG_HOST }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx electron-forge publish --arch=arm64,x64 --platform=darwin
working-directory: apps/x/apps/main
- name: Cleanup keychain
if: always()
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
if [ -f "$KEYCHAIN_PATH" ]; then
security delete-keychain "$KEYCHAIN_PATH" || true
fi
- name: Upload workflow artifacts
uses: actions/upload-artifact@v6
with:
name: distributables
path: apps/x/apps/main/out/make/*
retention-days: 30
build-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'pnpm'
cache-dependency-path: 'apps/x/pnpm-lock.yaml'
- name: Extract version from tag
id: version
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Extracted version: ${VERSION}"
- name: Update package.json versions
run: |
node -e "
const fs = require('fs');
const version = '${{ steps.version.outputs.version }}';
// Update apps/x/package.json
const rootPackage = JSON.parse(fs.readFileSync('apps/x/package.json', 'utf8'));
rootPackage.version = version;
fs.writeFileSync('apps/x/package.json', JSON.stringify(rootPackage, null, 2) + '\n');
// Update apps/x/apps/main/package.json
const mainPackage = JSON.parse(fs.readFileSync('apps/x/apps/main/package.json', 'utf8'));
mainPackage.version = version;
fs.writeFileSync('apps/x/apps/main/package.json', JSON.stringify(mainPackage, null, 2) + '\n');
console.log('Updated version to:', version);
"
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: apps/x
- name: Build electron app
env:
VITE_PUBLIC_POSTHOG_KEY: ${{ secrets.VITE_PUBLIC_POSTHOG_KEY }}
VITE_PUBLIC_POSTHOG_HOST: ${{ secrets.VITE_PUBLIC_POSTHOG_HOST }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx electron-forge publish --arch=x64,arm64 --platform=linux
working-directory: apps/x/apps/main
- name: Upload workflow artifacts
uses: actions/upload-artifact@v6
with:
name: distributables-linux
path: apps/x/apps/main/out/make/*
retention-days: 30
build-windows:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'pnpm'
cache-dependency-path: 'apps/x/pnpm-lock.yaml'
- name: Extract version from tag
id: version
shell: bash
run: |
VERSION="${GITHUB_REF#refs/tags/v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Extracted version: ${VERSION}"
- name: Update package.json versions
shell: bash
run: |
node -e "
const fs = require('fs');
const version = '${{ steps.version.outputs.version }}';
// Update apps/x/package.json
const rootPackage = JSON.parse(fs.readFileSync('apps/x/package.json', 'utf8'));
rootPackage.version = version;
fs.writeFileSync('apps/x/package.json', JSON.stringify(rootPackage, null, 2) + '\n');
// Update apps/x/apps/main/package.json
const mainPackage = JSON.parse(fs.readFileSync('apps/x/apps/main/package.json', 'utf8'));
mainPackage.version = version;
fs.writeFileSync('apps/x/apps/main/package.json', JSON.stringify(mainPackage, null, 2) + '\n');
console.log('Updated version to:', version);
"
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: apps/x
- name: Build electron app
env:
VITE_PUBLIC_POSTHOG_KEY: ${{ secrets.VITE_PUBLIC_POSTHOG_KEY }}
VITE_PUBLIC_POSTHOG_HOST: ${{ secrets.VITE_PUBLIC_POSTHOG_HOST }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx electron-forge publish --arch=x64 --platform=win32
working-directory: apps/x/apps/main
- name: Upload workflow artifacts
uses: actions/upload-artifact@v6
with:
name: distributables-windows
path: apps/x/apps/main/out/make/*
retention-days: 30
================================================
FILE: .github/workflows/rowboat-build.yml
================================================
name: Rowboat Build
on:
pull_request:
jobs:
build-rowboat-nextjs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
cache-dependency-path: 'apps/rowboat/package-lock.json'
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
working-directory: apps/rowboat
- name: Build Rowboat
run: npm run build
working-directory: apps/rowboat
build-rowboatx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
cache-dependency-path: 'apps/rowboat/package-lock.json'
node-version: '24'
cache: 'npm'
- name: Install dependencies
run: npm ci
working-directory: apps/cli
- name: Build Rowboat
run: npm run build
working-directory: apps/cli
================================================
FILE: .github/workflows/x-publish.yml
================================================
name: Publish to npm
on: workflow_dispatch
permissions:
id-token: write # Required for OIDC
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: 24
registry-url: https://registry.npmjs.org/
- name: Update npm
run: npm install -g npm@latest
- name: Install deps
run: npm ci
working-directory: apps/cli
# optional: run tests
# - run: npm test
- name: Build
run: npm run build
working-directory: apps/cli
- name: Pack
run: npm pack
working-directory: apps/cli
- name: Publish to npm
run: npm publish --access public
working-directory: apps/cli
================================================
FILE: .gitignore
================================================
.DS_Store
.env
.vscode/
data/
.venv/
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md - AI Coding Agent Context
This file provides context for AI coding agents working on the Rowboat monorepo.
## Quick Reference Commands
```bash
# Electron App (apps/x)
cd apps/x && pnpm install # Install dependencies
cd apps/x && npm run deps # Build workspace packages (shared → core → preload)
cd apps/x && npm run dev # Development mode (builds deps, runs app)
cd apps/x && npm run lint # Lint check
cd apps/x/apps/main && npm run package # Production build (.app)
cd apps/x/apps/main && npm run make # Create DMG distributable
```
## Monorepo Structure
```
rowboat/
├── apps/
│ ├── x/ # Electron desktop app (focus of this doc)
│ ├── rowboat/ # Next.js web dashboard
│ ├── rowboatx/ # Next.js frontend
│ ├── cli/ # CLI tool
│ ├── python-sdk/ # Python SDK
│ └── docs/ # Documentation site
├── CLAUDE.md # This file
└── README.md # User-facing readme
```
## Electron App Architecture (`apps/x`)
The Electron app is a **nested pnpm workspace** with its own package management.
```
apps/x/
├── package.json # Workspace root, dev scripts
├── pnpm-workspace.yaml # Defines workspace packages
├── pnpm-lock.yaml # Lockfile
├── apps/
│ ├── main/ # Electron main process
│ │ ├── src/ # Main process source
│ │ ├── forge.config.cjs # Electron Forge config
│ │ └── bundle.mjs # esbuild bundler
│ ├── renderer/ # React UI (Vite)
│ │ ├── src/ # React components
│ │ └── vite.config.ts
│ └── preload/ # Electron preload scripts
│ └── src/
└── packages/
├── shared/ # @x/shared - Types, utilities, validators
└── core/ # @x/core - Business logic, AI, OAuth, MCP
```
### Build Order (Dependencies)
```
shared (no deps)
↓
core (depends on shared)
↓
preload (depends on shared)
↓
renderer (depends on shared)
main (depends on shared, core)
```
**The `npm run deps` command builds:** shared → core → preload
### Key Entry Points
| Component | Entry | Output |
|-----------|-------|--------|
| main | `apps/main/src/main.ts` | `.package/dist/main.cjs` |
| renderer | `apps/renderer/src/main.tsx` | `apps/renderer/dist/` |
| preload | `apps/preload/src/preload.ts` | `apps/preload/dist/preload.js` |
## Build System
- **Package manager:** pnpm (required for `workspace:*` protocol)
- **Main bundler:** esbuild (bundles to single CommonJS file)
- **Renderer bundler:** Vite
- **Packaging:** Electron Forge
- **TypeScript:** ES2022 target
### Why esbuild bundling?
pnpm uses symlinks for workspace packages. Electron Forge's dependency walker can't follow these symlinks. esbuild bundles everything into a single file, eliminating the need for node_modules in the packaged app.
## Key Files Reference
| Purpose | File |
|---------|------|
| Electron main entry | `apps/x/apps/main/src/main.ts` |
| React app entry | `apps/x/apps/renderer/src/main.tsx` |
| Forge config (packaging) | `apps/x/apps/main/forge.config.cjs` |
| Main process bundler | `apps/x/apps/main/bundle.mjs` |
| Vite config | `apps/x/apps/renderer/vite.config.ts` |
| Shared types | `apps/x/packages/shared/src/` |
| Core business logic | `apps/x/packages/core/src/` |
| Workspace config | `apps/x/pnpm-workspace.yaml` |
| Root scripts | `apps/x/package.json` |
## Common Tasks
### LLM configuration (single provider)
- Config file: `~/.rowboat/config/models.json`
- Schema: `{ provider: { flavor, apiKey?, baseURL?, headers? }, model: string }`
- Models catalog cache: `~/.rowboat/config/models.dev.json` (OpenAI/Anthropic/Google only)
### Add a new shared type
1. Edit `apps/x/packages/shared/src/`
2. Run `cd apps/x && npm run deps` to rebuild
### Modify main process
1. Edit `apps/x/apps/main/src/`
2. Restart dev server (main doesn't hot-reload)
### Modify renderer (React UI)
1. Edit `apps/x/apps/renderer/src/`
2. Changes hot-reload automatically in dev mode
### Add a new dependency to main
1. `cd apps/x/apps/main && pnpm add <package>`
2. Import in source - esbuild will bundle it
### Verify compilation
```bash
cd apps/x && npm run deps && npm run lint
```
## Tech Stack
| Layer | Technology |
|-------|------------|
| Desktop | Electron 39.x |
| UI | React 19, Vite 7 |
| Styling | TailwindCSS, Radix UI |
| State | React hooks |
| AI | Vercel AI SDK, OpenAI/Anthropic/Google/OpenRouter providers, Vercel AI Gateway, Ollama, models.dev catalog |
| IPC | Electron contextBridge |
| Build | TypeScript 5.9, esbuild, Electron Forge |
## Environment Variables (for packaging)
For production builds with code signing:
- `APPLE_ID` - Apple Developer ID
- `APPLE_PASSWORD` - App-specific password
- `APPLE_TEAM_ID` - Team ID
Not required for local development.
================================================
FILE: Dockerfile.qdrant
================================================
FROM qdrant/qdrant:latest
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2024] [RowBoat Labs]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
<a href="https://www.youtube.com/watch?v=5AWoGo-L16I" target="_blank" rel="noopener noreferrer">
<img width="1339" height="607" alt="rowboat-github-2" src="https://github.com/user-attachments/assets/fc463b99-01b3-401c-b4a4-044dad480901" />
</a>
<h5 align="center">
<p align="center" style="display: flex; justify-content: center; gap: 20px; align-items: center;">
<a href="https://trendshift.io/repositories/13609" target="blank">
<img src="https://trendshift.io/api/badge/repositories/13609" alt="rowboatlabs/rowboat | Trendshift" width="250" height="55"/>
</a>
</p>
<p align="center">
<a href="https://www.rowboatlabs.com/" target="_blank" rel="noopener">
<img alt="Website" src="https://img.shields.io/badge/Website-10b981?labelColor=10b981&logo=window&logoColor=white">
</a>
<a href="https://discord.gg/wajrgmJQ6b" target="_blank" rel="noopener">
<img alt="Discord" src="https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=white&labelColor=5865F2">
</a>
<a href="https://x.com/intent/user?screen_name=rowboatlabshq" target="_blank" rel="noopener">
<img alt="Twitter" src="https://img.shields.io/twitter/follow/rowboatlabshq?style=social">
</a>
<a href="https://www.ycombinator.com" target="_blank" rel="noopener">
<img alt="Y Combinator" src="https://img.shields.io/badge/Y%20Combinator-S24-orange">
</a>
</p>
# Rowboat
**Open-source AI coworker that turns work into a knowledge graph and acts on it**
</h5>
Rowboat connects to your email and meeting notes, builds a long-lived knowledge graph, and uses that context to help you get work done - privately, on your machine.
You can do things like:
- `Build me a deck about our next quarter roadmap` → generates a PDF using context from your knowledge graph
- `Prep me for my meeting with Alex` → pulls past decisions, open questions, and relevant threads into a crisp brief (or a voice note)
- Visualize, edit, and update your knowledge graph anytime (it’s just Markdown)
- Record voice memos that automatically capture and update key takeaways in the graph
Download latest for Mac/Windows/Linux: [Download](https://www.rowboatlabs.com/downloads)
## Demo
[](https://www.youtube.com/watch?v=5AWoGo-L16I)
[Watch the full video](https://www.youtube.com/watch?v=5AWoGo-L16I)
---
## Installation
**Download latest for Mac/Windows/Linux:** [Download](https://www.rowboatlabs.com/downloads)
**All release files:** https://github.com/rowboatlabs/rowboat/releases/latest
### Google setup
To connect Google services (Gmail, Calendar, and Drive), follow [Google setup](https://github.com/rowboatlabs/rowboat/blob/main/google-setup.md).
### Voice notes
To enable voice notes (optional), add a Deepgram API key in ~/.rowboat/config/deepgram.json:
```
{
"apiKey": "<key>"
}
```
### Web search
To use Brave web search (optional), add the Brave API key in ~/.rowboat/config/brave-search.json.
To use Exa research search (optional), add the Exa API key in ~/.rowboat/config/exa-search.json.
(same format as above)
## What it does
Rowboat is a **local-first AI coworker** that can:
- **Remember** the important context you don’t want to re-explain (people, projects, decisions, commitments)
- **Understand** what’s relevant right now (before a meeting, while replying to an email, when writing a doc)
- **Help you act** by drafting, summarizing, planning, and producing real artifacts (briefs, emails, docs, PDF slides)
Under the hood, Rowboat maintains an **Obsidian-compatible vault** of plain Markdown notes with backlinks — a transparent “working memory” you can inspect and edit.
## Integrations
Rowboat builds memory from the work you already do, including:
- **Gmail** (email)
- **Granola** (meeting notes)
- **Fireflies** (meeting notes)
## How it’s different
Most AI tools reconstruct context on demand by searching transcripts or documents.
Rowboat maintains **long-lived knowledge** instead:
- context accumulates over time
- relationships are explicit and inspectable
- notes are editable by you, not hidden inside a model
- everything lives on your machine as plain Markdown
The result is memory that compounds, rather than retrieval that starts cold every time.
## What you can do with it
- **Meeting prep** from prior decisions, threads, and open questions
- **Email drafting** grounded in history and commitments
- **Docs & decks** generated from your ongoing context (including PDF slides)
- **Follow-ups**: capture decisions, action items, and owners so nothing gets dropped
- **On-your-machine help**: create files, summarize into notes, and run workflows using local tools (with explicit, reviewable actions)
## Background agents
Rowboat can spin up **background agents** to do repeatable work automatically - so routine tasks happen without you having to ask every time.
Examples:
- Draft email replies in the background (grounded in your past context and commitments)
- Generate a daily voice note each morning (agenda, priorities, upcoming meetings)
- Create recurring project updates from the latest emails/notes
- Keep your knowledge graph up to date as new information comes in
You control what runs, when it runs, and what gets written back into your local Markdown vault.
## Bring your own model
Rowboat works with the model setup you prefer:
- **Local models** via Ollama or LM Studio
- **Hosted models** (bring your own API key/provider)
- Swap models anytime — your data stays in your local Markdown vault
## Extend Rowboat with tools (MCP)
Rowboat can connect to external tools and services via **Model Context Protocol (MCP)**.
That means you can plug in (for example) search, databases, CRMs, support tools, and automations - or your own internal tools.
Examples: Exa (web search), Twitter/X, ElevenLabs (voice), Slack, Linear/Jira, GitHub, and more.
## Local-first by design
- All data is stored locally as plain Markdown
- No proprietary formats or hosted lock-in
- You can inspect, edit, back up, or delete everything at any time
---
<div align="center">
[Discord](https://discord.gg/wajrgmJQ6b) · [Twitter](https://x.com/intent/user?screen_name=rowboatlabshq)
</div>
================================================
FILE: apps/cli/.gitignore
================================================
node_modules/
dist/
.vercel
================================================
FILE: apps/cli/bin/app.js
================================================
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { app, modelConfig, importExample, listExamples, exportWorkflow } from '../dist/app.js';
import { runTui } from '../dist/tui/index.js';
yargs(hideBin(process.argv))
.command(
"$0",
"Run rowboatx",
(y) => y
.option("agent", {
type: "string",
description: "The agent to run",
default: "copilot",
})
.option("run_id", {
type: "string",
description: "Continue an existing run",
})
.option("input", {
type: "string",
description: "The input to the agent",
})
.option("no-interactive", {
type: "boolean",
description: "Do not interact with the user",
default: false,
}),
(argv) => {
app({
agent: argv.agent,
runId: argv.run_id,
input: argv.input,
noInteractive: argv.noInteractive,
});
}
)
.command(
"ui",
"Launch the interactive Rowboat dashboard",
(y) => y
.option("server-url", {
type: "string",
description: "Rowboat server base URL",
}),
(argv) => {
runTui({
serverUrl: argv.serverUrl,
});
}
)
.command(
"import",
"Import an example workflow (--example) or custom workflow from file (--file)",
(y) => y
.option("example", {
type: "string",
description: "Name of built-in example to import",
})
.option("file", {
type: "string",
description: "Path to custom workflow JSON file",
})
.check((argv) => {
if (!argv.example && !argv.file) {
throw new Error("Either --example or --file must be provided");
}
if (argv.example && argv.file) {
throw new Error("Cannot use both --example and --file at the same time");
}
return true;
}),
async (argv) => {
try {
if (argv.example) {
await importExample(String(argv.example).trim());
} else if (argv.file) {
await importExample(undefined, String(argv.file).trim());
}
} catch (error) {
console.error("Error:", error?.message ?? error);
process.exit(1);
}
}
)
.command(
"list-examples",
"List all available example workflows",
(y) => y,
async () => {
try {
const examples = await listExamples();
if (examples.length === 0) {
console.error("No packaged examples are available to list.");
return;
}
for (const example of examples) {
console.log(example);
}
} catch (error) {
console.error(error?.message ?? error);
process.exit(1);
}
}
)
.command(
"export",
"Export a workflow with all dependencies (outputs to stdout)",
(y) => y
.option("agent", {
type: "string",
description: "Entry agent name to export",
demandOption: true,
}),
async (argv) => {
try {
await exportWorkflow(String(argv.agent).trim());
} catch (error) {
console.error("Error:", error?.message ?? error);
process.exit(1);
}
}
)
.command(
"model-config",
"Select model",
(y) => y,
(argv) => {
modelConfig();
}
)
.parse();
================================================
FILE: apps/cli/package.json
================================================
{
"name": "@rowboatlabs/rowboatx",
"version": "0.16.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rm -rf dist && tsc",
"server": "node dist/server.js",
"migrate-agents": "node dist/scripts/migrate-agents.js"
},
"files": [
"dist",
"bin"
],
"bin": {
"rowboatx": "bin/app.js"
},
"keywords": [],
"author": "Rowboat Labs",
"license": "Apache-2.0",
"description": "",
"devDependencies": {
"@types/node": "^24.9.1",
"@types/react": "^18.3.12",
"typescript": "^5.9.3"
},
"dependencies": {
"@ai-sdk/anthropic": "^2.0.44",
"@ai-sdk/google": "^2.0.25",
"@ai-sdk/openai": "^2.0.53",
"@ai-sdk/openai-compatible": "^1.0.27",
"@ai-sdk/provider": "^2.0.0",
"@google-cloud/local-auth": "^3.0.1",
"@hono/node-server": "^1.19.6",
"@hono/standard-validator": "^0.1.5",
"@modelcontextprotocol/sdk": "^1.20.2",
"@openrouter/ai-sdk-provider": "^1.2.6",
"ai": "^5.0.102",
"awilix": "^12.0.5",
"eventsource-parser": "^1.1.2",
"google-auth-library": "^10.5.0",
"googleapis": "^169.0.0",
"hono": "^4.10.7",
"hono-openapi": "^1.1.1",
"ink": "^5.1.0",
"ink-select-input": "^6.2.0",
"ink-spinner": "^5.0.0",
"ink-text-input": "^6.0.0",
"json-schema-to-zod": "^2.6.1",
"nanoid": "^5.1.6",
"node-html-markdown": "^2.0.0",
"ollama-ai-provider-v2": "^1.5.4",
"react": "^18.3.1",
"yaml": "^2.8.2",
"yargs": "^18.0.0",
"zod": "^4.1.12"
}
}
================================================
FILE: apps/cli/src/agents/agents.ts
================================================
import { z } from "zod";
export const BaseTool = z.object({
name: z.string(),
});
export const BuiltinTool = BaseTool.extend({
type: z.literal("builtin"),
});
export const McpTool = BaseTool.extend({
type: z.literal("mcp"),
description: z.string(),
inputSchema: z.any(),
mcpServerName: z.string(),
});
export const AgentAsATool = BaseTool.extend({
type: z.literal("agent"),
});
export const ToolAttachment = z.discriminatedUnion("type", [
BuiltinTool,
McpTool,
AgentAsATool,
]);
export const Agent = z.object({
name: z.string(),
provider: z.string().optional(),
model: z.string().optional(),
description: z.string().optional(),
instructions: z.string(),
tools: z.record(z.string(), ToolAttachment).optional(),
});
================================================
FILE: apps/cli/src/agents/repo.ts
================================================
import { WorkDir } from "../config/config.js";
import fs from "fs/promises";
import { glob } from "node:fs/promises";
import path from "path";
import z from "zod";
import { Agent } from "./agents.js";
import { parse, stringify } from "yaml";
const UpdateAgentSchema = Agent.omit({ name: true });
export interface IAgentsRepo {
list(): Promise<z.infer<typeof Agent>[]>;
fetch(id: string): Promise<z.infer<typeof Agent>>;
create(agent: z.infer<typeof Agent>): Promise<void>;
update(id: string, agent: z.infer<typeof Agent>): Promise<void>;
delete(id: string): Promise<void>;
}
export class FSAgentsRepo implements IAgentsRepo {
private readonly agentsDir = path.join(WorkDir, "agents");
async list(): Promise<z.infer<typeof Agent>[]> {
const result: z.infer<typeof Agent>[] = [];
// list all md files in workdir/agents/
const matches = await Array.fromAsync(glob("**/*.md", { cwd: this.agentsDir }));
for (const file of matches) {
try {
const agent = await this.parseAgentMd(path.join(this.agentsDir, file));
result.push(agent);
} catch (error) {
console.error(`Error parsing agent ${file}: ${error instanceof Error ? error.message : String(error)}`);
continue;
}
}
return result;
}
private async parseAgentMd(filePath: string): Promise<z.infer<typeof Agent>> {
const raw = await fs.readFile(filePath, "utf8");
// strip the path prefix from the file name
// and the .md extension
const agentName = filePath
.replace(this.agentsDir + "/", "")
.replace(/\.md$/, "");
let agent: z.infer<typeof Agent> = {
name: agentName,
instructions: raw,
};
let content = raw;
// check for frontmatter markers at start
if (raw.startsWith("---")) {
const end = raw.indexOf("\n---", 3);
if (end !== -1) {
const fm = raw.slice(3, end).trim(); // YAML text
content = raw.slice(end + 4).trim(); // body after frontmatter
const yaml = parse(fm);
const parsed = Agent
.omit({ name: true, instructions: true })
.parse(yaml);
agent = {
...agent,
...parsed,
instructions: content,
};
}
}
return agent;
}
async fetch(id: string): Promise<z.infer<typeof Agent>> {
return this.parseAgentMd(path.join(this.agentsDir, `${id}.md`));
}
async create(agent: z.infer<typeof Agent>): Promise<void> {
const { instructions, ...rest } = agent;
const contents = `---\n${stringify(rest)}\n---\n${instructions}`;
await fs.writeFile(path.join(this.agentsDir, `${agent.name}.md`), contents);
}
async update(id: string, agent: z.infer<typeof UpdateAgentSchema>): Promise<void> {
const { instructions, ...rest } = agent;
const contents = `---\n${stringify(rest)}\n---\n${instructions}`;
await fs.writeFile(path.join(this.agentsDir, `${id}.md`), contents);
}
async delete(id: string): Promise<void> {
await fs.unlink(path.join(this.agentsDir, `${id}.md`));
}
}
================================================
FILE: apps/cli/src/agents/runtime.ts
================================================
import { jsonSchema, ModelMessage, modelMessageSchema } from "ai";
import fs from "fs";
import path from "path";
import { WorkDir } from "../config/config.js";
import { Agent, ToolAttachment } from "./agents.js";
import { AssistantContentPart, AssistantMessage, Message, MessageList, ProviderOptions, ToolCallPart, ToolMessage, UserMessage } from "../entities/message.js";
import { LanguageModel, stepCountIs, streamText, tool, Tool, ToolSet } from "ai";
import { z } from "zod";
import { LlmStepStreamEvent } from "../entities/llm-step-events.js";
import { execTool } from "../application/lib/exec-tool.js";
import { MessageEvent, AskHumanRequestEvent, RunEvent, ToolInvocationEvent, ToolPermissionRequestEvent, ToolPermissionResponseEvent } from "../entities/run-events.js";
import { BuiltinTools } from "../application/lib/builtin-tools.js";
import { CopilotAgent } from "../application/assistant/agent.js";
import { isBlocked } from "../application/lib/command-executor.js";
import container from "../di/container.js";
import { IModelConfigRepo } from "../models/repo.js";
import { getProvider } from "../models/models.js";
import { IAgentsRepo } from "./repo.js";
import { IdGen, IMonotonicallyIncreasingIdGenerator } from "../application/lib/id-gen.js";
import { IBus } from "../application/lib/bus.js";
import { IMessageQueue } from "../application/lib/message-queue.js";
import { IRunsRepo } from "../runs/repo.js";
import { IRunsLock } from "../runs/lock.js";
import { PrefixLogger } from "../shared/prefix-logger.js";
export interface IAgentRuntime {
trigger(runId: string): Promise<void>;
}
export class AgentRuntime implements IAgentRuntime {
private runsRepo: IRunsRepo;
private idGenerator: IMonotonicallyIncreasingIdGenerator;
private bus: IBus;
private messageQueue: IMessageQueue;
private modelConfigRepo: IModelConfigRepo;
private runsLock: IRunsLock;
constructor({
runsRepo,
idGenerator,
bus,
messageQueue,
modelConfigRepo,
runsLock,
}: {
runsRepo: IRunsRepo;
idGenerator: IMonotonicallyIncreasingIdGenerator;
bus: IBus;
messageQueue: IMessageQueue;
modelConfigRepo: IModelConfigRepo;
runsLock: IRunsLock;
}) {
this.runsRepo = runsRepo;
this.idGenerator = idGenerator;
this.bus = bus;
this.messageQueue = messageQueue;
this.modelConfigRepo = modelConfigRepo;
this.runsLock = runsLock;
}
async trigger(runId: string): Promise<void> {
if (!await this.runsLock.lock(runId)) {
console.log(`unable to acquire lock on run ${runId}`);
return;
}
try {
await this.bus.publish({
runId,
type: "run-processing-start",
subflow: [],
});
while (true) {
let eventCount = 0;
const run = await this.runsRepo.fetch(runId);
if (!run) {
throw new Error(`Run ${runId} not found`);
}
const state = new AgentState();
for (const event of run.log) {
state.ingest(event);
}
for await (const event of streamAgent({
state,
idGenerator: this.idGenerator,
runId,
messageQueue: this.messageQueue,
modelConfigRepo: this.modelConfigRepo,
})) {
eventCount++;
if (event.type !== "llm-stream-event") {
await this.runsRepo.appendEvents(runId, [event]);
}
await this.bus.publish(event);
}
// if no events, break
if (!eventCount) {
break;
}
}
} finally {
await this.runsLock.release(runId);
await this.bus.publish({
runId,
type: "run-processing-end",
subflow: [],
});
}
}
}
export async function mapAgentTool(t: z.infer<typeof ToolAttachment>): Promise<Tool> {
switch (t.type) {
case "mcp":
return tool({
name: t.name,
description: t.description,
inputSchema: jsonSchema(t.inputSchema),
});
case "agent":
const agent = await loadAgent(t.name);
if (!agent) {
throw new Error(`Agent ${t.name} not found`);
}
return tool({
name: t.name,
description: agent.description,
inputSchema: z.object({
message: z.string().describe("The message to send to the workflow"),
}),
});
case "builtin":
if (t.name === "ask-human") {
return tool({
description: "Ask a human before proceeding",
inputSchema: z.object({
question: z.string().describe("The question to ask the human"),
}),
});
}
const match = BuiltinTools[t.name];
if (!match) {
throw new Error(`Unknown builtin tool: ${t.name}`);
}
return tool({
description: match.description,
inputSchema: match.inputSchema,
});
}
}
export class RunLogger {
private logFile: string;
private fileHandle: fs.WriteStream;
ensureRunsDir() {
const runsDir = path.join(WorkDir, "runs");
if (!fs.existsSync(runsDir)) {
fs.mkdirSync(runsDir, { recursive: true });
}
}
constructor(runId: string) {
this.ensureRunsDir();
this.logFile = path.join(WorkDir, "runs", `${runId}.jsonl`);
this.fileHandle = fs.createWriteStream(this.logFile, {
flags: "a",
encoding: "utf8",
});
}
log(event: z.infer<typeof RunEvent>) {
if (event.type !== "llm-stream-event") {
this.fileHandle.write(JSON.stringify(event) + "\n");
}
}
close() {
this.fileHandle.close();
}
}
export class StreamStepMessageBuilder {
private parts: z.infer<typeof AssistantContentPart>[] = [];
private textBuffer: string = "";
private reasoningBuffer: string = "";
private providerOptions: z.infer<typeof ProviderOptions> | undefined = undefined;
flushBuffers() {
// skip reasoning
// if (this.reasoningBuffer) {
// this.parts.push({ type: "reasoning", text: this.reasoningBuffer });
// this.reasoningBuffer = "";
// }
if (this.textBuffer) {
this.parts.push({ type: "text", text: this.textBuffer });
this.textBuffer = "";
}
}
ingest(event: z.infer<typeof LlmStepStreamEvent>) {
switch (event.type) {
case "reasoning-start":
case "reasoning-end":
case "text-start":
case "text-end":
this.flushBuffers();
break;
case "reasoning-delta":
this.reasoningBuffer += event.delta;
break;
case "text-delta":
this.textBuffer += event.delta;
break;
case "tool-call":
this.parts.push({
type: "tool-call",
toolCallId: event.toolCallId,
toolName: event.toolName,
arguments: event.input,
providerOptions: event.providerOptions,
});
break;
case "finish-step":
this.providerOptions = event.providerOptions;
break;
}
}
get(): z.infer<typeof AssistantMessage> {
this.flushBuffers();
return {
role: "assistant",
content: this.parts,
providerOptions: this.providerOptions,
};
}
}
function normaliseAskHumanToolCall(message: z.infer<typeof AssistantMessage>) {
if (typeof message.content === "string") {
return;
}
let askHumanToolCall: z.infer<typeof ToolCallPart> | null = null;
const newParts = [];
for (const part of message.content as z.infer<typeof AssistantContentPart>[]) {
if (part.type === "tool-call" && part.toolName === "ask-human") {
if (!askHumanToolCall) {
askHumanToolCall = part;
} else {
(askHumanToolCall as z.infer<typeof ToolCallPart>).arguments += "\n" + part.arguments;
}
break;
} else {
newParts.push(part);
}
}
if (askHumanToolCall) {
newParts.push(askHumanToolCall);
}
message.content = newParts;
}
export async function loadAgent(id: string): Promise<z.infer<typeof Agent>> {
if (id === "copilot" || id === "rowboatx") {
return CopilotAgent;
}
const repo = container.resolve<IAgentsRepo>('agentsRepo');
return await repo.fetch(id);
}
export function convertFromMessages(messages: z.infer<typeof Message>[]): ModelMessage[] {
const result: ModelMessage[] = [];
for (const msg of messages) {
const { providerOptions } = msg;
switch (msg.role) {
case "assistant":
if (typeof msg.content === 'string') {
result.push({
role: "assistant",
content: msg.content,
providerOptions,
});
} else {
result.push({
role: "assistant",
content: msg.content.map(part => {
switch (part.type) {
case 'text':
return part;
case 'reasoning':
return part;
case 'tool-call':
return {
type: 'tool-call',
toolCallId: part.toolCallId,
toolName: part.toolName,
input: part.arguments,
providerOptions: part.providerOptions,
};
}
}),
providerOptions,
});
}
break;
case "system":
result.push({
role: "system",
content: msg.content,
providerOptions,
});
break;
case "user":
result.push({
role: "user",
content: msg.content,
providerOptions,
});
break;
case "tool":
result.push({
role: "tool",
content: [
{
type: "tool-result",
toolCallId: msg.toolCallId,
toolName: msg.toolName,
output: {
type: "text",
value: msg.content,
},
},
],
providerOptions,
});
break;
}
}
// doing this because: https://github.com/OpenRouterTeam/ai-sdk-provider/issues/262
return JSON.parse(JSON.stringify(result));
}
async function buildTools(agent: z.infer<typeof Agent>): Promise<ToolSet> {
const tools: ToolSet = {};
for (const [name, tool] of Object.entries(agent.tools ?? {})) {
try {
tools[name] = await mapAgentTool(tool);
} catch (error) {
console.error(`Error mapping tool ${name}:`, error);
continue;
}
}
return tools;
}
export class AgentState {
runId: string | null = null;
agent: z.infer<typeof Agent> | null = null;
agentName: string | null = null;
messages: z.infer<typeof MessageList> = [];
lastAssistantMsg: z.infer<typeof AssistantMessage> | null = null;
subflowStates: Record<string, AgentState> = {};
toolCallIdMap: Record<string, z.infer<typeof ToolCallPart>> = {};
pendingToolCalls: Record<string, true> = {};
pendingToolPermissionRequests: Record<string, z.infer<typeof ToolPermissionRequestEvent>> = {};
pendingAskHumanRequests: Record<string, z.infer<typeof AskHumanRequestEvent>> = {};
allowedToolCallIds: Record<string, true> = {};
deniedToolCallIds: Record<string, true> = {};
getPendingPermissions(): z.infer<typeof ToolPermissionRequestEvent>[] {
const response: z.infer<typeof ToolPermissionRequestEvent>[] = [];
for (const [id, subflowState] of Object.entries(this.subflowStates)) {
for (const perm of subflowState.getPendingPermissions()) {
response.push({
...perm,
subflow: [id, ...perm.subflow],
});
}
}
for (const perm of Object.values(this.pendingToolPermissionRequests)) {
response.push({
...perm,
subflow: [],
});
}
return response;
}
getPendingAskHumans(): z.infer<typeof AskHumanRequestEvent>[] {
const response: z.infer<typeof AskHumanRequestEvent>[] = [];
for (const [id, subflowState] of Object.entries(this.subflowStates)) {
for (const ask of subflowState.getPendingAskHumans()) {
response.push({
...ask,
subflow: [id, ...ask.subflow],
});
}
}
for (const ask of Object.values(this.pendingAskHumanRequests)) {
response.push({
...ask,
subflow: [],
});
}
return response;
}
finalResponse(): string {
if (!this.lastAssistantMsg) {
return '';
}
if (typeof this.lastAssistantMsg.content === "string") {
return this.lastAssistantMsg.content;
}
return this.lastAssistantMsg.content.reduce((acc, part) => {
if (part.type === "text") {
return acc + part.text;
}
return acc;
}, "");
}
ingest(event: z.infer<typeof RunEvent>) {
if (event.subflow.length > 0) {
const { subflow, ...rest } = event;
if (!this.subflowStates[subflow[0]]) {
this.subflowStates[subflow[0]] = new AgentState();
}
this.subflowStates[subflow[0]].ingest({
...rest,
subflow: subflow.slice(1),
});
return;
}
switch (event.type) {
case "start":
this.runId = event.runId;
this.agentName = event.agentName;
break;
case "spawn-subflow":
// Seed the subflow state with its agent so downstream loadAgent works.
if (!this.subflowStates[event.toolCallId]) {
this.subflowStates[event.toolCallId] = new AgentState();
}
this.subflowStates[event.toolCallId].agentName = event.agentName;
break;
case "message":
this.messages.push(event.message);
if (event.message.content instanceof Array) {
for (const part of event.message.content) {
if (part.type === "tool-call") {
this.toolCallIdMap[part.toolCallId] = part;
this.pendingToolCalls[part.toolCallId] = true;
}
}
}
if (event.message.role === "tool") {
const message = event.message as z.infer<typeof ToolMessage>;
delete this.pendingToolCalls[message.toolCallId];
}
if (event.message.role === "assistant") {
this.lastAssistantMsg = event.message;
}
break;
case "tool-permission-request":
this.pendingToolPermissionRequests[event.toolCall.toolCallId] = event;
break;
case "tool-permission-response":
switch (event.response) {
case "approve":
this.allowedToolCallIds[event.toolCallId] = true;
break;
case "deny":
this.deniedToolCallIds[event.toolCallId] = true;
break;
}
delete this.pendingToolPermissionRequests[event.toolCallId];
break;
case "ask-human-request":
this.pendingAskHumanRequests[event.toolCallId] = event;
break;
case "ask-human-response":
// console.error('im here', this.agentName, this.runId, event.subflow);
const ogEvent = this.pendingAskHumanRequests[event.toolCallId];
this.messages.push({
role: "tool",
content: JSON.stringify({
userResponse: event.response,
}),
toolCallId: ogEvent.toolCallId,
toolName: this.toolCallIdMap[ogEvent.toolCallId]!.toolName,
});
delete this.pendingAskHumanRequests[ogEvent.toolCallId];
break;
}
}
}
export async function* streamAgent({
state,
idGenerator,
runId,
messageQueue,
modelConfigRepo,
}: {
state: AgentState,
idGenerator: IMonotonicallyIncreasingIdGenerator;
runId: string;
messageQueue: IMessageQueue;
modelConfigRepo: IModelConfigRepo;
}): AsyncGenerator<z.infer<typeof RunEvent>, void, unknown> {
const logger = new PrefixLogger(`run-${runId}-${state.agentName}`);
async function* processEvent(event: z.infer<typeof RunEvent>): AsyncGenerator<z.infer<typeof RunEvent>, void, unknown> {
state.ingest(event);
yield event;
}
const modelConfig = await modelConfigRepo.getConfig();
if (!modelConfig) {
throw new Error("Model config not found");
}
// set up agent
const agent = await loadAgent(state.agentName!);
// set up tools
const tools = await buildTools(agent);
// set up provider + model
const provider = await getProvider(agent.provider);
const model = provider.languageModel(agent.model || modelConfig.defaults.model);
let loopCounter = 0;
while (true) {
loopCounter++;
let loopLogger = logger.child(`iter-${loopCounter}`);
loopLogger.log('starting loop iteration');
// execute any pending tool calls
for (const toolCallId of Object.keys(state.pendingToolCalls)) {
const toolCall = state.toolCallIdMap[toolCallId];
let _logger = loopLogger.child(`tc-${toolCallId}-${toolCall.toolName}`);
_logger.log('processing');
// if ask-human, skip
if (toolCall.toolName === "ask-human") {
_logger.log('skipping, reason: ask-human');
continue;
}
// if tool has been denied, deny
if (state.deniedToolCallIds[toolCallId]) {
_logger.log('returning denied tool message, reason: tool has been denied');
yield* processEvent({
runId,
messageId: await idGenerator.next(),
type: "message",
message: {
role: "tool",
content: "Unable to execute this tool: Permission was denied.",
toolCallId: toolCallId,
toolName: toolCall.toolName,
},
subflow: [],
});
continue;
}
// if permission is pending on this tool call, skip execution
if (state.pendingToolPermissionRequests[toolCallId]) {
_logger.log('skipping, reason: permission is pending');
continue;
}
// execute approved tool
_logger.log('executing tool');
yield* processEvent({
runId,
type: "tool-invocation",
toolCallId,
toolName: toolCall.toolName,
input: JSON.stringify(toolCall.arguments),
subflow: [],
});
let result: any = null;
if (agent.tools![toolCall.toolName].type === "agent") {
let subflowState = state.subflowStates[toolCallId];
for await (const event of streamAgent({
state: subflowState,
idGenerator,
runId,
messageQueue,
modelConfigRepo,
})) {
yield* processEvent({
...event,
subflow: [toolCallId, ...event.subflow],
});
}
if (!subflowState.getPendingAskHumans().length && !subflowState.getPendingPermissions().length) {
result = subflowState.finalResponse();
}
} else {
result = await execTool(agent.tools![toolCall.toolName], toolCall.arguments);
}
if (result) {
const resultMsg: z.infer<typeof ToolMessage> = {
role: "tool",
content: JSON.stringify(result),
toolCallId: toolCall.toolCallId,
toolName: toolCall.toolName,
};
yield* processEvent({
runId,
type: "tool-result",
toolCallId: toolCall.toolCallId,
toolName: toolCall.toolName,
result: result,
subflow: [],
});
yield* processEvent({
runId,
messageId: await idGenerator.next(),
type: "message",
message: resultMsg,
subflow: [],
});
}
}
// if waiting on user permission or ask-human, exit
if (state.getPendingAskHumans().length || state.getPendingPermissions().length) {
loopLogger.log('exiting loop, reason: pending asks or permissions');
return;
}
// get any queued user messages
while (true) {
const msg = await messageQueue.dequeue(runId);
if (!msg) {
break;
}
loopLogger.log('dequeued user message', msg.messageId);
yield* processEvent({
runId,
type: "message",
messageId: msg.messageId,
message: {
role: "user",
content: msg.message,
},
subflow: [],
});
}
// if last response is from assistant and text, exit
const lastMessage = state.messages[state.messages.length - 1];
if (lastMessage
&& lastMessage.role === "assistant"
&& (typeof lastMessage.content === "string"
|| !lastMessage.content.some(part => part.type === "tool-call")
)
) {
loopLogger.log('exiting loop, reason: last message is from assistant and text');
return;
}
// run one LLM turn.
loopLogger.log('running llm turn');
// stream agent response and build message
const messageBuilder = new StreamStepMessageBuilder();
for await (const event of streamLlm(
model,
state.messages,
agent.instructions,
tools,
)) {
loopLogger.log('got llm-stream-event:', event.type)
messageBuilder.ingest(event);
yield* processEvent({
runId,
type: "llm-stream-event",
event: event,
subflow: [],
});
}
// build and emit final message from agent response
const message = messageBuilder.get();
yield* processEvent({
runId,
messageId: await idGenerator.next(),
type: "message",
message,
subflow: [],
});
// if there were any ask-human calls, emit those events
if (message.content instanceof Array) {
for (const part of message.content) {
if (part.type === "tool-call") {
const underlyingTool = agent.tools![part.toolName];
if (underlyingTool.type === "builtin" && underlyingTool.name === "ask-human") {
loopLogger.log('emitting ask-human-request, toolCallId:', part.toolCallId);
yield* processEvent({
runId,
type: "ask-human-request",
toolCallId: part.toolCallId,
query: part.arguments.question,
subflow: [],
});
}
if (underlyingTool.type === "builtin" && underlyingTool.name === "executeCommand") {
// if command is blocked, then seek permission
if (isBlocked(part.arguments.command)) {
loopLogger.log('emitting tool-permission-request, toolCallId:', part.toolCallId);
yield* processEvent({
runId,
type: "tool-permission-request",
toolCall: part,
subflow: [],
});
}
}
if (underlyingTool.type === "agent" && underlyingTool.name) {
loopLogger.log('emitting spawn-subflow, toolCallId:', part.toolCallId);
yield* processEvent({
runId,
type: "spawn-subflow",
agentName: underlyingTool.name,
toolCallId: part.toolCallId,
subflow: [],
});
yield* processEvent({
runId,
messageId: await idGenerator.next(),
type: "message",
message: {
role: "user",
content: part.arguments.message,
},
subflow: [part.toolCallId],
});
}
}
}
}
}
}
async function* streamLlm(
model: LanguageModel,
messages: z.infer<typeof MessageList>,
instructions: string,
tools: ToolSet,
): AsyncGenerator<z.infer<typeof LlmStepStreamEvent>, void, unknown> {
const { fullStream } = streamText({
model,
messages: convertFromMessages(messages),
system: instructions,
tools,
stopWhen: stepCountIs(1),
});
for await (const event of fullStream) {
// console.log("\n\n\t>>>>\t\tstream event", JSON.stringify(event));
switch (event.type) {
case "reasoning-start":
yield {
type: "reasoning-start",
providerOptions: event.providerMetadata,
};
break;
case "reasoning-delta":
yield {
type: "reasoning-delta",
delta: event.text,
providerOptions: event.providerMetadata,
};
break;
case "reasoning-end":
yield {
type: "reasoning-end",
providerOptions: event.providerMetadata,
};
break;
case "text-start":
yield {
type: "text-start",
providerOptions: event.providerMetadata,
};
break;
case "text-delta":
yield {
type: "text-delta",
delta: event.text,
providerOptions: event.providerMetadata,
};
break;
case "tool-call":
yield {
type: "tool-call",
toolCallId: event.toolCallId,
toolName: event.toolName,
input: event.input,
providerOptions: event.providerMetadata,
};
break;
case "finish-step":
yield {
type: "finish-step",
usage: event.usage,
finishReason: event.finishReason,
providerOptions: event.providerMetadata,
};
break;
default:
// console.warn("Unknown event type", event);
continue;
}
}
}
export const MappedToolCall = z.object({
toolCall: ToolCallPart,
agentTool: ToolAttachment,
});
================================================
FILE: apps/cli/src/app.ts
================================================
import { AgentState, streamAgent } from "./agents/runtime.js";
import { StreamRenderer } from "./application/lib/stream-renderer.js";
import { stdin as input, stdout as output } from "node:process";
import fs from "fs";
import { promises as fsp } from "fs";
import path from "path";
import { WorkDir } from "./config/config.js";
import { RunEvent } from "./entities/run-events.js";
import { createInterface, Interface } from "node:readline/promises";
import { ToolCallPart } from "./entities/message.js";
import { Agent } from "./agents/agents.js";
import { McpServerConfig, McpServerDefinition } from "./mcp/schema.js";
import { Example } from "./entities/example.js";
import { z } from "zod";
import { Flavor } from "./models/models.js";
import { examples } from "./examples/index.js";
import container from "./di/container.js";
import { IModelConfigRepo } from "./models/repo.js";
function renderGreeting() {
const logo = `
$$\\ $$\\
$$ | $$ |
$$$$$$\\ $$$$$$\\ $$\\ $$\\ $$\\ $$$$$$$\\ $$$$$$\\ $$$$$$\\ $$$$$$\\ $$\\ $$\\
$$ __$$\\ $$ __$$\\ $$ | $$ | $$ |$$ __$$\\ $$ __$$\\ \\____$$\\_$$ _| \\$$\\ $$ |
$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$ | $$ |$$ / $$ | $$$$$$$ | $$ | \\$$$$ /
$$ | $$ | $$ |$$ | $$ | $$ |$$ | $$ |$$ | $$ |$$ __$$ | $$ |$$\\ $$ $$<
$$ | \\$$$$$$ |\\$$$$$\\$$$$ |$$$$$$$ |\\$$$$$$ |\\$$$$$$$ | \\$$$$ |$$ /\\$$\\
\\__| \\______/ \\_____\\____/ \\_______/ \\______/ \\_______| \\____/ \\__/ \\__|
`;
console.log(logo);
console.log("\nHow can i help you today?");
}
export async function app(opts: {
agent: string;
runId?: string;
input?: string;
noInteractive?: boolean;
}) {
throw new Error("Not implemented");
/*
const renderer = new StreamRenderer();
const state = new AgentState(opts.agent, opts.runId);
if (opts.agent === "copilot" && !opts.runId) {
renderGreeting();
}
// load existing and assemble state if required
let runId = opts.runId;
if (runId) {
console.error("loading run", runId);
let stream: fs.ReadStream | null = null;
let rl: Interface | null = null;
try {
const logFile = path.join(WorkDir, "runs", `${runId}.jsonl`);
stream = fs.createReadStream(logFile, { encoding: "utf8" });
rl = createInterface({ input: stream, crlfDelay: Infinity });
for await (const line of rl) {
if (line.trim() === "") {
continue;
}
const parsed = JSON.parse(line);
const event = RunEvent.parse(parsed);
state.ingest(event);
}
} finally {
stream?.close();
}
}
let rl: Interface | null = null;
if (!opts.noInteractive) {
rl = createInterface({ input, output });
}
let inputConsumed = false;
try {
while (true) {
// ask for pending tool permissions
for (const perm of Object.values(state.getPendingPermissions())) {
if (opts.noInteractive) {
return;
}
const response = await getToolCallPermission(perm.toolCall, rl!);
state.ingestAndLog({
type: "tool-permission-response",
response,
toolCallId: perm.toolCall.toolCallId,
subflow: perm.subflow,
});
}
// ask for pending human input
for (const ask of Object.values(state.getPendingAskHumans())) {
if (opts.noInteractive) {
return;
}
const response = await getAskHumanResponse(ask.query, rl!);
state.ingestAndLog({
type: "ask-human-response",
response,
toolCallId: ask.toolCallId,
subflow: ask.subflow,
});
}
// run one turn
for await (const event of streamAgent(state)) {
renderer.render(event);
if (event?.type === "error") {
process.exitCode = 1;
}
}
// if nothing pending, get user input
if (state.getPendingPermissions().length === 0 && state.getPendingAskHumans().length === 0) {
if (opts.input && !inputConsumed) {
state.ingestAndLog({
type: "message",
message: {
role: "user",
content: opts.input,
},
subflow: [],
});
inputConsumed = true;
continue;
}
if (opts.noInteractive) {
return;
}
const response = await getUserInput(rl!);
state.ingestAndLog({
type: "message",
message: {
role: "user",
content: response,
},
subflow: [],
});
}
}
} finally {
rl?.close();
}
*/
}
async function getToolCallPermission(
call: z.infer<typeof ToolCallPart>,
rl: Interface,
): Promise<"approve" | "deny"> {
const question = `Do you want to allow running the following tool: ${call.toolName}?:
Tool name: ${call.toolName}
Tool arguments: ${JSON.stringify(call.arguments)}
Choices: y/n/a/d:
- y: approve
- n: deny
`;
const input = await rl.question(question);
if (input.toLowerCase() === "y") return "approve";
if (input.toLowerCase() === "n") return "deny";
return "deny";
}
async function getAskHumanResponse(
query: string,
rl: Interface,
): Promise<string> {
const input = await rl.question(`The agent is asking for your help with the following query:
Question: ${query}
Please respond to the question.
`);
return input;
}
async function getUserInput(
rl: Interface,
): Promise<string> {
const input = await rl.question("You: ");
if (["quit", "exit", "q"].includes(input.toLowerCase().trim())) {
console.error("Bye!");
process.exit(0);
}
return input;
}
export async function modelConfig() {
// load existing model config
const repo = container.resolve<IModelConfigRepo>('modelConfigRepo');
const config = await repo.getConfig();
const rl = createInterface({ input, output });
try {
const defaultApiKeyEnvVars: Record<z.infer<typeof Flavor>, string> = {
"rowboat [free]": "",
openai: "OPENAI_API_KEY",
aigateway: "AI_GATEWAY_API_KEY",
anthropic: "ANTHROPIC_API_KEY",
google: "GOOGLE_GENERATIVE_AI_API_KEY",
ollama: "",
"openai-compatible": "",
openrouter: "",
};
const defaultBaseUrls: Record<z.infer<typeof Flavor>, string> = {
"rowboat [free]": "",
openai: "https://api.openai.com/v1",
aigateway: "https://ai-gateway.vercel.sh/v1/ai",
anthropic: "https://api.anthropic.com/v1",
google: "https://generativelanguage.googleapis.com/v1beta",
ollama: "http://localhost:11434",
"openai-compatible": "http://localhost:8080/v1",
openrouter: "https://openrouter.ai/api/v1",
};
const defaultModels: Record<z.infer<typeof Flavor>, string> = {
"rowboat [free]": "google/gemini-3-pro-preview",
openai: "gpt-5.1",
aigateway: "gpt-5.1",
anthropic: "claude-sonnet-4-5",
google: "gemini-2.5-pro",
ollama: "llama3.1",
"openai-compatible": "openai/gpt-5.1",
openrouter: "openrouter/auto",
};
const currentProvider = config?.defaults?.provider;
const currentModel = config?.defaults?.model;
const currentProviderConfig = currentProvider ? config?.providers?.[currentProvider] : undefined;
if (config) {
renderCurrentModel(currentProvider || "none", currentProviderConfig?.flavor || "", currentModel || "none");
}
const FlavorList = [...Flavor.options];
const flavorPromptLines = FlavorList
.map((f, idx) => ` ${idx + 1}. ${f}`)
.join("\n");
const flavorAnswer = await rl.question(
`Select a provider type:\n${flavorPromptLines}\nEnter number or name: `
);
let selectedFlavorRaw = flavorAnswer.trim();
let selectedFlavor: z.infer<typeof Flavor> | null = null;
if (/^\d+$/.test(selectedFlavorRaw)) {
const idx = parseInt(selectedFlavorRaw, 10) - 1;
if (idx >= 0 && idx < FlavorList.length) {
selectedFlavor = FlavorList[idx];
}
} else if (FlavorList.includes(selectedFlavorRaw as z.infer<typeof Flavor>)) {
selectedFlavor = selectedFlavorRaw as z.infer<typeof Flavor>;
}
if (!selectedFlavor) {
console.error("Invalid selection. Exiting.");
return;
}
const existingAliases = Object.keys(config?.providers || {}).filter(
(name) => config?.providers?.[name]?.flavor === selectedFlavor,
);
let providerName: string | null = null;
let chooseMode: "existing" | "add" = "add";
if (existingAliases.length > 0) {
const listLines = existingAliases
.map((alias, idx) => ` ${idx + 1}. use existing: ${alias}`)
.join("\n");
const addIndex = existingAliases.length + 1;
const providerSelect = await rl.question(
`Found existing providers for ${selectedFlavor}:\n${listLines}\n ${addIndex}. add new\nEnter number or name/alias [${addIndex}]: `,
);
const sel = providerSelect.trim();
if (sel === "" || sel.toLowerCase() === "add" || sel.toLowerCase() === "new") {
chooseMode = "add";
} else if (/^\d+$/.test(sel)) {
const idx = parseInt(sel, 10) - 1;
if (idx >= 0 && idx < existingAliases.length) {
providerName = existingAliases[idx];
chooseMode = "existing";
} else if (idx === existingAliases.length) {
chooseMode = "add";
} else {
console.error("Invalid selection. Exiting.");
return;
}
} else if (existingAliases.includes(sel)) {
providerName = sel;
chooseMode = "existing";
} else {
console.error("Invalid selection. Exiting.");
return;
}
}
if (chooseMode === "existing" && !providerName) {
console.error("No provider selected. Exiting.");
return;
}
if (chooseMode === "existing") {
const modelDefault =
currentProvider === providerName && currentModel
? currentModel
: defaultModels[selectedFlavor];
const modelAns = await rl.question(
`Specify model for ${selectedFlavor} [${modelDefault}]: `,
);
const model = modelAns.trim() || modelDefault;
await repo.setDefault(providerName!, model);
console.log(`Model configuration updated. Provider set to '${providerName}'.`);
return;
}
const headers: Record<string, string> = {};
if (selectedFlavor !== "rowboat [free]") {
const providerNameAns = await rl.question(
`Enter a name/alias for this provider [${selectedFlavor}]: `,
);
providerName = providerNameAns.trim() || selectedFlavor;
} else {
providerName = selectedFlavor;
}
let baseURL: string | undefined = undefined;
if (selectedFlavor !== "rowboat [free]") {
const baseUrlAns = await rl.question(
`Enter baseURL for ${selectedFlavor} [${defaultBaseUrls[selectedFlavor]}]: `,
);
baseURL = baseUrlAns.trim() || undefined;
}
let apiKey: string | undefined = undefined;
if (selectedFlavor !== "ollama" && selectedFlavor !== "rowboat [free]") {
let autopickText = "";
if (defaultApiKeyEnvVars[selectedFlavor]) {
autopickText = ` (leave blank to pick from environment variable ${defaultApiKeyEnvVars[selectedFlavor]})`;
}
const apiKeyAns = await rl.question(
`Enter API key for ${selectedFlavor}${autopickText}: `,
);
apiKey = apiKeyAns.trim() || undefined;
}
if (selectedFlavor === "ollama") {
const keyAns = await rl.question(
`Enter API key for ${selectedFlavor} (optional): `
);
const key = keyAns.trim();
if (key) {
headers["Authorization"] = `Bearer ${key}`;
}
}
const modelDefault = defaultModels[selectedFlavor];
const modelAns = await rl.question(
`Specify model for ${selectedFlavor} [${modelDefault}]: `,
);
const model = modelAns.trim() || modelDefault;
await repo.upsert(providerName, {
flavor: selectedFlavor,
apiKey,
baseURL,
headers,
});
await repo.setDefault(providerName, model);
renderCurrentModel(providerName, selectedFlavor, model);
console.log(`Configuration written to ${WorkDir}/config/models.json. You can also edit this file manually`);
} finally {
rl.close();
}
}
function renderCurrentModel(provider: string, flavor: string, model: string) {
console.log("Currently using:");
console.log(`- provider: ${provider}${flavor ? ` (${flavor})` : ""}`);
console.log(`- model: ${model}`);
console.log("");
}
async function listAvailableExamples(): Promise<string[]> {
return Object.keys(examples);
}
async function writeAgents(agents: z.infer<typeof Agent>[] | undefined) {
if (!agents) {
return;
}
await fsp.mkdir(path.join(WorkDir, "agents"), { recursive: true });
await Promise.all(
agents.map(async (agent) => {
const agentPath = path.join(WorkDir, "agents", `${agent.name}.json`);
await fsp.writeFile(agentPath, JSON.stringify(agent, null, 2), "utf8");
}),
);
}
async function mergeMcpServers(servers: Record<string, z.infer<typeof McpServerDefinition>>) {
const result = { added: [] as string[], skipped: [] as string[] };
// Early return if no servers to process
if (!servers || Object.keys(servers).length === 0) {
return result;
}
const configPath = path.join(WorkDir, "config", "mcp.json");
// Read existing config
let currentConfig: z.infer<typeof McpServerConfig> = { mcpServers: {} };
try {
const contents = await fsp.readFile(configPath, "utf8");
currentConfig = McpServerConfig.parse(JSON.parse(contents));
} catch (error: any) {
if (error?.code !== "ENOENT") {
throw new Error(`Unable to read MCP config: ${error.message ?? error}`);
}
// File doesn't exist yet, use empty config
}
// Merge servers
for (const [name, definition] of Object.entries(servers)) {
if (currentConfig.mcpServers[name]) {
result.skipped.push(name);
} else {
currentConfig.mcpServers[name] = definition;
result.added.push(name);
}
}
// Only write if we added new servers
if (result.added.length > 0) {
await fsp.mkdir(path.dirname(configPath), { recursive: true });
await fsp.writeFile(configPath, JSON.stringify(currentConfig, null, 2), "utf8");
}
return result;
}
export async function importExample(exampleName?: string, filePath?: string) {
let example: z.infer<typeof Example>;
let sourceName: string;
if (exampleName) {
// Load from built-in examples
example = examples[exampleName];
if (!example) {
const availableExamples = Object.keys(examples);
const listMessage = availableExamples.length
? `Available examples: ${availableExamples.join(", ")}`
: "No packaged examples are available.";
throw new Error(`Unknown example '${exampleName}'. ${listMessage}`);
}
sourceName = exampleName;
} else if (filePath) {
// Load from file path
try {
const fileContent = await fsp.readFile(filePath, "utf8");
example = Example.parse(JSON.parse(fileContent));
sourceName = path.basename(filePath, ".json");
} catch (error: any) {
if (error?.code === "ENOENT") {
throw new Error(`File not found: ${filePath}`);
} else if (error?.name === "ZodError") {
throw new Error(`Invalid workflow file format: ${error.message}`);
}
throw new Error(`Failed to read workflow file: ${error.message ?? error}`);
}
} else {
throw new Error("Either exampleName or filePath must be provided");
}
// Import agents and MCP servers
await writeAgents(example.agents);
let serverMerge = { added: [] as string[], skipped: [] as string[] };
if (example.mcpServers) {
serverMerge = await mergeMcpServers(example.mcpServers);
}
// Build and display output message
const importedAgents = example.agents?.map((agent) => agent.name) ?? [];
const entryAgent = example.entryAgent ?? importedAgents[0] ?? "";
const output = [
`✓ Imported workflow '${sourceName}'`,
` Agents: ${importedAgents.join(", ")}`,
` Primary: ${entryAgent}`,
];
if (serverMerge.added.length > 0) {
output.push(` MCP servers added: ${serverMerge.added.join(", ")}`);
}
if (serverMerge.skipped.length > 0) {
output.push(` MCP servers skipped (already configured): ${serverMerge.skipped.join(", ")}`);
}
console.log(output.join("\n"));
// Display post-install instructions if present
if (example.instructions) {
console.log("\n" + "=".repeat(60));
console.log("POST-INSTALL INSTRUCTIONS");
console.log("=".repeat(60));
console.log(example.instructions);
console.log("=".repeat(60) + "\n");
}
// Display next steps
console.log(`\nRun: rowboatx --agent ${entryAgent}`);
}
export async function listExamples() {
return listAvailableExamples();
}
export async function exportWorkflow(entryAgentName: string) {
const agentsDir = path.join(WorkDir, "agents");
const mcpConfigPath = path.join(WorkDir, "config", "mcp.json");
// Read MCP config
let mcpConfig: z.infer<typeof McpServerConfig> = { mcpServers: {} };
try {
const mcpContent = await fsp.readFile(mcpConfigPath, "utf8");
mcpConfig = McpServerConfig.parse(JSON.parse(mcpContent));
} catch (error: any) {
if (error?.code !== "ENOENT") {
throw new Error(`Failed to read MCP config: ${error.message ?? error}`);
}
}
// Recursively discover all agents and MCP servers
const discoveredAgents = new Map<string, z.infer<typeof Agent>>();
const discoveredMcpServers = new Set<string>();
async function discoverAgent(agentName: string) {
if (discoveredAgents.has(agentName)) {
return; // Already processed
}
// Load agent
const agentPath = path.join(agentsDir, `${agentName}.json`);
let agentContent: string;
try {
agentContent = await fsp.readFile(agentPath, "utf8");
} catch (error: any) {
if (error?.code === "ENOENT") {
throw new Error(`Agent not found: ${agentName}`);
}
throw new Error(`Failed to read agent ${agentName}: ${error.message ?? error}`);
}
const agent = Agent.parse(JSON.parse(agentContent));
discoveredAgents.set(agentName, agent);
// Process tools
if (agent.tools) {
for (const [toolKey, tool] of Object.entries(agent.tools)) {
if (tool.type === "agent") {
// Recursively discover dependent agent
await discoverAgent(tool.name);
} else if (tool.type === "mcp") {
// Track MCP server
discoveredMcpServers.add(tool.mcpServerName);
}
}
}
}
// Start discovery from entry agent
await discoverAgent(entryAgentName);
// Build MCP servers object
const workflowMcpServers: Record<string, z.infer<typeof McpServerDefinition>> = {};
for (const serverName of discoveredMcpServers) {
if (mcpConfig.mcpServers[serverName]) {
workflowMcpServers[serverName] = mcpConfig.mcpServers[serverName];
} else {
throw new Error(`MCP server '${serverName}' is referenced but not found in config`);
}
}
// Build workflow object
const workflow: z.infer<typeof Example> = {
id: entryAgentName,
entryAgent: entryAgentName,
agents: Array.from(discoveredAgents.values()),
...(Object.keys(workflowMcpServers).length > 0 ? { mcpServers: workflowMcpServers } : {}),
};
// Output to stdout
console.log(JSON.stringify(workflow, null, 2));
}
================================================
FILE: apps/cli/src/application/assistant/agent.ts
================================================
import { Agent, ToolAttachment } from "../../agents/agents.js";
import z from "zod";
import { CopilotInstructions } from "./instructions.js";
import { BuiltinTools } from "../lib/builtin-tools.js";
const tools: Record<string, z.infer<typeof ToolAttachment>> = {};
for (const [name, tool] of Object.entries(BuiltinTools)) {
tools[name] = {
type: "builtin",
name,
};
}
export const CopilotAgent: z.infer<typeof Agent> = {
name: "rowboatx",
description: "Rowboatx copilot",
instructions: CopilotInstructions,
tools,
}
================================================
FILE: apps/cli/src/application/assistant/instructions.ts
================================================
import { skillCatalog } from "./skills/index.js";
import { WorkDir as BASE_DIR } from "../../config/config.js";
import { getRuntimeContext, getRuntimeContextPrompt } from "./runtime-context.js";
const runtimeContextPrompt = getRuntimeContextPrompt(getRuntimeContext());
export const CopilotInstructions = `You are an intelligent workflow assistant helping users manage their workflows in ${BASE_DIR}. You can also help the user with general tasks.
## General Capabilities
In addition to Rowboat-specific workflow management, you can help users with general tasks like answering questions, explaining concepts, brainstorming ideas, solving problems, writing and debugging code, analyzing information, and providing explanations on a wide range of topics. Be conversational, helpful, and engaging. For tasks requiring external capabilities (web search, APIs, etc.), use MCP tools as described below.
Use the catalog below to decide which skills to load for each user request. Before acting:
- Call the \`loadSkill\` tool with the skill's name or path so you can read its guidance string.
- Apply the instructions from every loaded skill while working on the request.
${skillCatalog}
Always consult this catalog first so you load the right skills before taking action.
# Communication & Execution Style
## Communication principles
- Be concise and direct. Avoid verbose explanations unless the user asks for details.
- Only show JSON output when explicitly requested by the user. Otherwise, summarize results in plain language.
- Break complex efforts into clear, sequential steps the user can follow.
- Explain reasoning briefly as you work, and confirm outcomes before moving on.
- Be proactive about understanding missing context; ask clarifying questions when needed.
- Summarize completed work and suggest logical next steps at the end of a task.
- Always ask for confirmation before taking destructive actions.
## MCP Tool Discovery (CRITICAL)
**ALWAYS check for MCP tools BEFORE saying you can't do something.**
When a user asks for ANY task that might require external capabilities (web search, internet access, APIs, data fetching, etc.), check MCP tools first using \`listMcpServers\` and \`listMcpTools\`. Load the "mcp-integration" skill for detailed guidance on discovering and executing MCP tools.
**DO NOT** immediately respond with "I can't access the internet" or "I don't have that capability" without checking MCP tools first!
## Execution reminders
- Explore existing files and structure before creating new assets.
- Use relative paths (no \${BASE_DIR} prefixes) when running commands or referencing files.
- Keep user data safe—double-check before editing or deleting important resources.
${runtimeContextPrompt}
## Workspace access & scope
- You have full read/write access inside \`${BASE_DIR}\` (this resolves to the user's \`~/.rowboat\` directory). Create folders, files, and agents there using builtin tools or allowed shell commands—don't wait for the user to do it manually.
- If a user mentions a different root (e.g., \`~/.rowboatx\` or another path), clarify whether they meant the Rowboat workspace and propose the equivalent path you can act on. Only refuse if they explicitly insist on an inaccessible location.
- Prefer builtin file tools (\`createFile\`, \`updateFile\`, \`deleteFile\`, \`exploreDirectory\`) for workspace changes. Reserve refusal or "you do it" responses for cases that are truly outside the Rowboat sandbox.
## Builtin Tools vs Shell Commands
**IMPORTANT**: Rowboat provides builtin tools that are internal and do NOT require security allowlist entries:
- \`deleteFile\`, \`createFile\`, \`updateFile\`, \`readFile\` - File operations
- \`listFiles\`, \`exploreDirectory\` - Directory exploration
- \`analyzeAgent\` - Agent analysis
- \`addMcpServer\`, \`listMcpServers\`, \`listMcpTools\`, \`executeMcpTool\` - MCP server management and execution
- \`loadSkill\` - Skill loading
These tools work directly and are NOT filtered by \`.rowboat/config/security.json\`.
**CRITICAL: MCP Server Configuration**
- ALWAYS use the \`addMcpServer\` builtin tool to add or update MCP servers—it validates the configuration before saving
- NEVER manually edit \`config/mcp.json\` using \`createFile\` or \`updateFile\` for MCP servers
- Invalid MCP configs will prevent the agent from starting with validation errors
**Only \`executeCommand\` (shell/bash commands) is filtered** by the security allowlist. If you need to delete a file, use the \`deleteFile\` builtin tool, not \`executeCommand\` with \`rm\`. If you need to create a file, use \`createFile\`, not \`executeCommand\` with \`touch\` or \`echo >\`.
The security allowlist in \`security.json\` only applies to shell commands executed via \`executeCommand\`, not to Rowboat's internal builtin tools.
`;
================================================
FILE: apps/cli/src/application/assistant/runtime-context.ts
================================================
export type RuntimeShellDialect = 'windows-cmd' | 'posix-sh';
export type RuntimeOsName = 'Windows' | 'macOS' | 'Linux' | 'Unknown';
export interface RuntimeContext {
platform: NodeJS.Platform;
osName: RuntimeOsName;
shellDialect: RuntimeShellDialect;
shellExecutable: string;
}
export function getExecutionShell(platform: NodeJS.Platform = process.platform): string {
return platform === 'win32' ? (process.env.ComSpec || 'cmd.exe') : '/bin/sh';
}
export function getRuntimeContext(platform: NodeJS.Platform = process.platform): RuntimeContext {
if (platform === 'win32') {
return {
platform,
osName: 'Windows',
shellDialect: 'windows-cmd',
shellExecutable: getExecutionShell(platform),
};
}
if (platform === 'darwin') {
return {
platform,
osName: 'macOS',
shellDialect: 'posix-sh',
shellExecutable: getExecutionShell(platform),
};
}
if (platform === 'linux') {
return {
platform,
osName: 'Linux',
shellDialect: 'posix-sh',
shellExecutable: getExecutionShell(platform),
};
}
return {
platform,
osName: 'Unknown',
shellDialect: 'posix-sh',
shellExecutable: getExecutionShell(platform),
};
}
export function getRuntimeContextPrompt(runtime: RuntimeContext): string {
if (runtime.shellDialect === 'windows-cmd') {
return `## Runtime Platform (CRITICAL)
- Detected platform: **${runtime.platform}**
- Detected OS: **${runtime.osName}**
- Shell used by executeCommand: **${runtime.shellExecutable}** (Windows Command Prompt / cmd syntax)
- Use Windows command syntax for executeCommand (for example: \`dir\`, \`type\`, \`copy\`, \`move\`, \`del\`, \`rmdir\`).
- Use Windows-style absolute paths when outside workspace (for example: \`C:\\Users\\...\`).
- Do not assume macOS/Linux command syntax when the runtime is Windows.`;
}
return `## Runtime Platform (CRITICAL)
- Detected platform: **${runtime.platform}**
- Detected OS: **${runtime.osName}**
- Shell used by executeCommand: **${runtime.shellExecutable}** (POSIX sh syntax)
- Use POSIX command syntax for executeCommand (for example: \`ls\`, \`cat\`, \`cp\`, \`mv\`, \`rm\`).
- Use POSIX paths when outside workspace (for example: \`~/Desktop\`, \`/Users/.../\` on macOS, \`/home/.../\` on Linux).
- Do not assume Windows command syntax when the runtime is POSIX.`;
}
================================================
FILE: apps/cli/src/application/assistant/skills/builtin-tools/skill.ts
================================================
export const skill = String.raw`
# Builtin Tools Reference
Load this skill when creating or modifying agents that need access to Rowboat's builtin tools (shell execution, file operations, etc.).
## Available Builtin Tools
Agents can use builtin tools by declaring them in the \`"tools"\` object with \`"type": "builtin"\` and the appropriate \`"name"\`.
### executeCommand
**The most powerful and versatile builtin tool** - Execute any bash/shell command and get the output.
**Security note:** Commands are filtered through \`.rowboat/config/security.json\`. Populate this file with allowed command names (array or dictionary entries). Any command not present is blocked and returns exit code 126 so the agent knows it violated the policy.
**Agent tool declaration:**
\`\`\`json
"tools": {
"bash": {
"type": "builtin",
"name": "executeCommand"
}
}
\`\`\`
**What it can do:**
- Run package managers (npm, pip, apt, brew, cargo, go get, etc.)
- Git operations (clone, commit, push, pull, status, diff, log, etc.)
- System operations (ps, top, df, du, find, grep, kill, etc.)
- Build and compilation (make, cargo build, go build, npm run build, etc.)
- Network operations (curl, wget, ping, ssh, netstat, etc.)
- Text processing (awk, sed, grep, jq, yq, cut, sort, uniq, etc.)
- Database operations (psql, mysql, mongo, redis-cli, etc.)
- Container operations (docker, kubectl, podman, etc.)
- Testing and debugging (pytest, jest, cargo test, etc.)
- File operations (cat, head, tail, wc, diff, patch, etc.)
- Any CLI tool or script execution
**Agent instruction examples:**
- "Use the bash tool to run git commands for version control operations"
- "Execute curl commands using the bash tool to fetch data from APIs"
- "Use bash to run 'npm install' and 'npm test' commands"
- "Run Python scripts using the bash tool with 'python script.py'"
- "Use bash to execute 'docker ps' and inspect container status"
- "Run database queries using 'psql' or 'mysql' commands via bash"
- "Use bash to execute system monitoring commands like 'top' or 'ps aux'"
**Pro tips for agent instructions:**
- Commands can be chained with && for sequential execution
- Use pipes (|) to combine Unix tools (e.g., "cat file.txt | grep pattern | wc -l")
- Redirect output with > or >> when needed
- Full bash shell features are available (variables, loops, conditionals, etc.)
- Tools like jq, yq, awk, sed can parse and transform data
**Example agent with executeCommand:**
\`\`\`json
{
"name": "arxiv-feed-reader",
"description": "A feed reader for the arXiv",
"model": "gpt-5.1",
"instructions": "Extract latest papers from the arXiv feed and summarize them. Use curl to fetch the RSS feed, then parse it with yq and jq:\n\ncurl -s https://rss.arxiv.org/rss/cs.AI | yq -p=xml -o=json | jq -r '.rss.channel.item[] | select(.title | test(\"agent\"; \"i\")) | \"\\(.title)\\n\\(.link)\\n\\(.description)\\n\"'\n\nThis will give you papers containing 'agent' in the title.",
"tools": {
"bash": {
"type": "builtin",
"name": "executeCommand"
}
}
}
\`\`\`
**Another example - System monitoring agent:**
\`\`\`json
{
"name": "system-monitor",
"description": "Monitor system resources and processes",
"model": "gpt-5.1",
"instructions": "Monitor system resources using bash commands. Use 'df -h' for disk usage, 'free -h' for memory, 'top -bn1' for processes, 'ps aux' for process list. Parse the output and report any issues.",
"tools": {
"bash": {
"type": "builtin",
"name": "executeCommand"
}
}
}
\`\`\`
**Another example - Git automation agent:**
\`\`\`json
{
"name": "git-helper",
"description": "Automate git operations",
"model": "gpt-5.1",
"instructions": "Help with git operations. Use commands like 'git status', 'git log --oneline -10', 'git diff', 'git branch -a' to inspect the repository. Can also run 'git add', 'git commit', 'git push' when instructed.",
"tools": {
"bash": {
"type": "builtin",
"name": "executeCommand"
}
}
}
\`\`\`
## Agent-to-Agent Calling
Agents can call other agents as tools to create complex multi-step workflows. This is the core mechanism for building multi-agent systems in the CLI.
**Tool declaration:**
\`\`\`json
"tools": {
"summariser": {
"type": "agent",
"name": "summariser_agent"
}
}
\`\`\`
**When to use:**
- Breaking complex tasks into specialized sub-agents
- Creating reusable agent components
- Orchestrating multi-step workflows
- Delegating specialized tasks (e.g., summarization, data processing, audio generation)
**How it works:**
- The agent calls the tool like any other tool
- The target agent receives the input and processes it
- Results are returned as tool output
- The calling agent can then continue processing or delegate further
**Example - Agent that delegates to a summarizer:**
\`\`\`json
{
"name": "paper_analyzer",
"model": "gpt-5.1",
"instructions": "Pick 2 interesting papers and summarise each using the summariser tool. Pass the paper URL to the summariser. Don't ask for human input.",
"tools": {
"summariser": {
"type": "agent",
"name": "summariser_agent"
}
}
}
\`\`\`
**Tips for agent chaining:**
- Make instructions explicit about when to call other agents
- Pass clear, structured data between agents
- Add "Don't ask for human input" for autonomous workflows
- Keep each agent focused on a single responsibility
## Additional Builtin Tools
While \`executeCommand\` is the most versatile, other builtin tools exist for specific Rowboat operations (file management, agent inspection, etc.). These are primarily used by the Rowboat copilot itself and are not typically needed in user agents. If you need file operations, consider using bash commands like \`cat\`, \`echo\`, \`tee\`, etc. through \`executeCommand\`.
### Copilot-Specific Builtin Tools
The Rowboat copilot has access to special builtin tools that regular agents don't typically use. These tools help the copilot assist users with workspace management and MCP integration:
#### File & Directory Operations
- \`exploreDirectory\` - Recursively explore directory structure
- \`readFile\` - Read and parse file contents
- \`createFile\` - Create a new file with content
- \`updateFile\` - Update or overwrite existing file contents
- \`deleteFile\` - Delete a file
- \`listFiles\` - List all files and directories
#### Agent Operations
- \`analyzeAgent\` - Read and analyze an agent file structure
- \`loadSkill\` - Load a Rowboat skill definition into context
#### MCP Operations
- \`addMcpServer\` - Add or update an MCP server configuration (with validation)
- \`listMcpServers\` - List all available MCP servers
- \`listMcpTools\` - List all available tools from a specific MCP server
- \`executeMcpTool\` - **Execute a specific MCP tool on behalf of the user**
#### Using executeMcpTool as Copilot
The \`executeMcpTool\` builtin allows the copilot to directly execute MCP tools without creating an agent. Load the "mcp-integration" skill for complete guidance on discovering and executing MCP tools, including workflows, schema matching, and examples.
**When to use executeMcpTool vs creating an agent:**
- Use \`executeMcpTool\` for immediate, one-time tasks
- Create an agent when the user needs repeated use or autonomous operation
- Create an agent for complex multi-step workflows involving multiple tools
## Best Practices
1. **Give agents clear examples** in their instructions showing exact bash commands to run
2. **Explain output parsing** - show how to use jq, yq, grep, awk to extract data
3. **Chain commands efficiently** - use && for sequences, | for pipes
4. **Handle errors** - remind agents to check exit codes and stderr
5. **Be specific** - provide example commands rather than generic descriptions
6. **Security** - remind agents to validate inputs and avoid dangerous operations
## When to Use Builtin Tools vs MCP Tools vs Agent Tools
- **Use builtin executeCommand** when you need: CLI tools, system operations, data processing, git operations, any shell command
- **Use MCP tools** when you need: Web scraping (firecrawl), text-to-speech (elevenlabs), specialized APIs, external service integrations
- **Use agent tools (\`"type": "agent"\`)** when you need: Complex multi-step logic, task delegation, specialized processing that benefits from LLM reasoning
Many tasks can be accomplished with just \`executeCommand\` and common Unix tools - it's incredibly powerful!
## Key Insight: Multi-Agent Workflows
In the CLI, multi-agent workflows are built by:
1. Creating specialized agents for specific tasks (in \`agents/\` directory)
2. Creating an orchestrator agent that has other agents in its \`tools\`
3. Running the orchestrator with \`rowboatx --agent orchestrator_name\`
There are no separate "workflow" files - everything is an agent!
`;
export default skill;
================================================
FILE: apps/cli/src/application/assistant/skills/deletion-guardrails/skill.ts
================================================
export const skill = String.raw`
# Deletion Guardrails
Load this skill when a user asks to delete agents or workflows so you follow the required confirmation steps.
## Workflow deletion protocol
1. Read the workflow file to identify every agent it references.
2. Report those agents to the user and ask whether they should be deleted too.
3. Wait for explicit confirmation before deleting anything.
4. Only remove the workflow and/or agents the user authorizes.
## Agent deletion protocol
1. Inspect the agent file to discover which workflows reference it.
2. List those workflows to the user and ask whether they should be updated or deleted.
3. Pause for confirmation before modifying workflows or removing the agent.
4. Perform only the deletions the user approves.
## Safety checklist
- Never delete cascaded resources automatically.
- Keep a clear audit trail in your responses describing what was removed.
- If the user’s instructions are ambiguous, ask clarifying questions before taking action.
`;
export default skill;
================================================
FILE: apps/cli/src/application/assistant/skills/index.ts
================================================
import path from "node:path";
import { fileURLToPath } from "node:url";
import builtinToolsSkill from "./builtin-tools/skill.js";
import deletionGuardrailsSkill from "./deletion-guardrails/skill.js";
import mcpIntegrationSkill from "./mcp-integration/skill.js";
import workflowAuthoringSkill from "./workflow-authoring/skill.js";
import workflowRunOpsSkill from "./workflow-run-ops/skill.js";
const CURRENT_FILE = fileURLToPath(import.meta.url);
const CURRENT_DIR = path.dirname(CURRENT_FILE);
const CATALOG_PREFIX = "src/application/assistant/skills";
type SkillDefinition = {
id: string;
title: string;
folder: string;
summary: string;
content: string;
};
type ResolvedSkill = {
id: string;
catalogPath: string;
content: string;
};
const definitions: SkillDefinition[] = [
{
id: "workflow-authoring",
title: "Workflow Authoring",
folder: "workflow-authoring",
summary: "Creating or editing workflows/agents, validating schema rules, and keeping filenames aligned with JSON ids.",
content: workflowAuthoringSkill,
},
{
id: "builtin-tools",
title: "Builtin Tools Reference",
folder: "builtin-tools",
summary: "Understanding and using builtin tools (especially executeCommand for bash/shell) in agent definitions.",
content: builtinToolsSkill,
},
{
id: "mcp-integration",
title: "MCP Integration Guidance",
folder: "mcp-integration",
summary: "Discovering, executing, and integrating MCP tools. Use this to check what external capabilities are available and execute MCP tools on behalf of users.",
content: mcpIntegrationSkill,
},
{
id: "deletion-guardrails",
title: "Deletion Guardrails",
folder: "deletion-guardrails",
summary: "Following the confirmation process before removing workflows or agents and their dependencies.",
content: deletionGuardrailsSkill,
},
{
id: "workflow-run-ops",
title: "Workflow Run Operations",
folder: "workflow-run-ops",
summary: "Commands that list workflow runs, inspect paused executions, or manage cron schedules for workflows.",
content: workflowRunOpsSkill,
},
];
const skillEntries = definitions.map((definition) => ({
...definition,
catalogPath: `${CATALOG_PREFIX}/${definition.folder}/skill.ts`,
}));
const catalogSections = skillEntries.map((entry) => [
`## ${entry.title}`,
`- **Skill file:** \`${entry.catalogPath}\``,
`- **Use it for:** ${entry.summary}`,
].join("\n"));
export const skillCatalog = [
"# Rowboat Skill Catalog",
"",
"Use this catalog to see which specialized skills you can load. Each entry lists the exact skill file plus a short description of when it helps.",
"",
catalogSections.join("\n\n"),
].join("\n");
const normalizeIdentifier = (value: string) =>
value.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
const aliasMap = new Map<string, ResolvedSkill>();
const registerAlias = (alias: string, entry: ResolvedSkill) => {
const normalized = normalizeIdentifier(alias);
if (!normalized) return;
aliasMap.set(normalized, entry);
};
const registerAliasVariants = (alias: string, entry: ResolvedSkill) => {
const normalized = normalizeIdentifier(alias);
if (!normalized) return;
const variants = new Set<string>([normalized]);
if (/\.(ts|js)$/i.test(normalized)) {
variants.add(normalized.replace(/\.(ts|js)$/i, ""));
variants.add(
normalized.endsWith(".ts") ? normalized.replace(/\.ts$/i, ".js") : normalized.replace(/\.js$/i, ".ts"),
);
} else {
variants.add(`${normalized}.ts`);
variants.add(`${normalized}.js`);
}
for (const variant of variants) {
registerAlias(variant, entry);
}
};
for (const entry of skillEntries) {
const absoluteTs = path.join(CURRENT_DIR, entry.folder, "skill.ts");
const absoluteJs = path.join(CURRENT_DIR, entry.folder, "skill.js");
const resolvedEntry: ResolvedSkill = {
id: entry.id,
catalogPath: entry.catalogPath,
content: entry.content,
};
const baseAliases = [
entry.id,
entry.folder,
`${entry.folder}/skill`,
`${entry.folder}/skill.ts`,
`${entry.folder}/skill.js`,
`skills/${entry.folder}/skill.ts`,
`skills/${entry.folder}/skill.js`,
`${CATALOG_PREFIX}/${entry.folder}/skill.ts`,
`${CATALOG_PREFIX}/${entry.folder}/skill.js`,
absoluteTs,
absoluteJs,
];
for (const alias of baseAliases) {
registerAliasVariants(alias, resolvedEntry);
}
}
export const availableSkills = skillEntries.map((entry) => entry.id);
export function resolveSkill(identifier: string): ResolvedSkill | null {
const normalized = normalizeIdentifier(identifier);
if (!normalized) return null;
return aliasMap.get(normalized) ?? null;
}
================================================
FILE: apps/cli/src/application/assistant/skills/mcp-integration/skill.ts
================================================
export const skill = String.raw`
# MCP Integration Guidance
**Load this skill proactively** when a user asks for ANY task that might require external capabilities (web search, internet access, APIs, data fetching, time/date, etc.). This skill provides complete guidance on discovering and executing MCP tools.
## CRITICAL: Always Check MCP Tools First
**IMPORTANT**: When a user asks for ANY task that might require external capabilities (web search, API calls, data fetching, etc.), ALWAYS:
1. **First check**: Call \`listMcpServers\` to see what's available
2. **Then list tools**: Call \`listMcpTools\` on relevant servers
3. **Execute if possible**: Use \`executeMcpTool\` if a tool matches the need
4. **Only then decline**: If no MCP tool can help, explain what's not possible
**DO NOT** immediately say "I can't do that" or "I don't have internet access" without checking MCP tools first!
### Common User Requests and MCP Tools
| User Request | Check For | Likely Tool |
|--------------|-----------|-------------|
| "Search the web/internet" | firecrawl, composio, fetch | \`firecrawl_search\`, \`COMPOSIO_SEARCH_WEB\` |
| "Scrape this website" | firecrawl | \`firecrawl_scrape\` |
| "Read/write files" | filesystem | \`read_file\`, \`write_file\` |
| "Get current time/date" | time | \`get_current_time\` |
| "Make HTTP request" | fetch | \`fetch\`, \`post\` |
| "GitHub operations" | github | \`create_issue\`, \`search_repos\` |
| "Generate audio/speech" | elevenLabs | \`text_to_speech\` |
| "Tweet/social media" | twitter, composio | Various social tools |
## Key concepts
- MCP servers expose tools (web scraping, APIs, databases, etc.) declared in \`config/mcp.json\`.
- Agents reference MCP tools through the \`"tools"\` block by specifying \`type\`, \`name\`, \`description\`, \`mcpServerName\`, and a full \`inputSchema\`.
- Tool schemas can include optional property descriptions; only include \`"required"\` when parameters are mandatory.
## CRITICAL: Adding MCP Servers
**ALWAYS use the \`addMcpServer\` builtin tool** to add or update MCP server configurations. This tool validates the configuration before saving and prevents startup errors.
**NEVER manually create or edit \`config/mcp.json\`** using \`createFile\` or \`updateFile\` for MCP servers—this bypasses validation and will cause errors.
### MCP Server Configuration Schema
There are TWO types of MCP servers:
#### 1. STDIO (Command-based) Servers
For servers that run as local processes (Node.js, Python, etc.):
**Required fields:**
- \`command\`: string (e.g., "npx", "node", "python", "uvx")
**Optional fields:**
- \`args\`: array of strings (command arguments)
- \`env\`: object with string key-value pairs (environment variables)
- \`type\`: "stdio" (optional, inferred from presence of \`command\`)
**Schema:**
\`\`\`json
{
"type": "stdio",
"command": "string (REQUIRED)",
"args": ["string", "..."],
"env": {
"KEY": "value"
}
}
\`\`\`
**Valid STDIO examples:**
\`\`\`json
{
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/data"]
}
\`\`\`
\`\`\`json
{
"command": "python",
"args": ["-m", "mcp_server_git"],
"env": {
"GIT_REPO_PATH": "/path/to/repo"
}
}
\`\`\`
\`\`\`json
{
"command": "uvx",
"args": ["mcp-server-fetch"]
}
\`\`\`
#### 2. HTTP/SSE Servers
For servers that expose HTTP or Server-Sent Events endpoints:
**Required fields:**
- \`url\`: string (complete URL including protocol and path)
**Optional fields:**
- \`headers\`: object with string key-value pairs (HTTP headers)
- \`type\`: "http" (optional, inferred from presence of \`url\`)
**Schema:**
\`\`\`json
{
"type": "http",
"url": "string (REQUIRED)",
"headers": {
"Authorization": "Bearer token",
"Custom-Header": "value"
}
}
\`\`\`
**Valid HTTP examples:**
\`\`\`json
{
"url": "http://localhost:3000/sse"
}
\`\`\`
\`\`\`json
{
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer sk-1234567890"
}
}
\`\`\`
### Common Validation Errors to Avoid
❌ **WRONG - Missing required field:**
\`\`\`json
{
"args": ["some-arg"]
}
\`\`\`
Error: Missing \`command\` for stdio OR \`url\` for http
❌ **WRONG - Empty object:**
\`\`\`json
{}
\`\`\`
Error: Must have either \`command\` (stdio) or \`url\` (http)
❌ **WRONG - Mixed types:**
\`\`\`json
{
"command": "npx",
"url": "http://localhost:3000"
}
\`\`\`
Error: Cannot have both \`command\` and \`url\`
✅ **CORRECT - Minimal stdio:**
\`\`\`json
{
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-time"]
}
\`\`\`
✅ **CORRECT - Minimal http:**
\`\`\`json
{
"url": "http://localhost:3000/sse"
}
\`\`\`
### Using addMcpServer Tool
**Example 1: Add stdio server**
\`\`\`json
{
"serverName": "filesystem",
"serverType": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/data"]
}
\`\`\`
**Example 2: Add HTTP server**
\`\`\`json
{
"serverName": "custom-api",
"serverType": "http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer token123"
}
}
\`\`\`
**Example 3: Add Python MCP server**
\`\`\`json
{
"serverName": "github",
"serverType": "stdio",
"command": "python",
"args": ["-m", "mcp_server_github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxx"
}
}
\`\`\`
## Operator actions
1. Use \`listMcpServers\` to enumerate configured servers.
2. Use \`addMcpServer\` to add or update MCP server configurations (with validation).
3. Use \`listMcpTools\` for a server to understand the available operations and schemas.
4. Use \`executeMcpTool\` to run MCP tools directly on behalf of the user.
5. Explain which MCP tools match the user's needs before editing agent definitions.
6. When adding a tool to an agent, document what it does and ensure the schema mirrors the MCP definition.
## Executing MCP Tools Directly (Copilot)
As the copilot, you can execute MCP tools directly on behalf of the user using the \`executeMcpTool\` builtin. This allows you to use MCP tools without creating an agent.
### When to Execute MCP Tools Directly
- User asks you to perform a task that an MCP tool can handle (web search, file operations, API calls, etc.)
- User wants immediate results from an MCP tool without setting up an agent
- You need to test or demonstrate an MCP tool's functionality
- You're helping the user accomplish a one-time task
### Workflow for Executing MCP Tools
1. **Discover available servers**: Use \`listMcpServers\` to see what MCP servers are configured
2. **List tools from a server**: Use \`listMcpTools\` with the server name to see available tools and their schemas
3. **CAREFULLY EXAMINE THE SCHEMA**: Look at the \`inputSchema\` to understand exactly what parameters are required
4. **Execute the tool**: Use \`executeMcpTool\` with the server name, tool name, and required arguments (matching the schema exactly)
5. **Return results**: Present the results to the user in a helpful format
### CRITICAL: Schema Matching
**ALWAYS** examine the \`inputSchema\` from \`listMcpTools\` before calling \`executeMcpTool\`.
The schema tells you:
- What parameters are required (check the \`"required"\` array)
- What type each parameter should be (string, number, boolean, object, array)
- Parameter descriptions and examples
**Example schema from listMcpTools:**
\`\`\`json
{
"name": "COMPOSIO_SEARCH_WEB",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query"
},
"limit": {
"type": "number",
"description": "Number of results"
}
},
"required": ["query"]
}
}
\`\`\`
**Correct executeMcpTool call:**
\`\`\`json
{
"serverName": "composio",
"toolName": "COMPOSIO_SEARCH_WEB",
"arguments": {
"query": "elon musk latest news"
}
}
\`\`\`
**WRONG - Missing arguments:**
\`\`\`json
{
"serverName": "composio",
"toolName": "COMPOSIO_SEARCH_WEB"
}
\`\`\`
**WRONG - Wrong parameter name:**
\`\`\`json
{
"serverName": "composio",
"toolName": "COMPOSIO_SEARCH_WEB",
"arguments": {
"search": "elon musk" // Wrong! Should be "query"
}
}
\`\`\`
### Example: Using Firecrawl to Search the Web
**Step 1: List servers**
\`\`\`json
// Call: listMcpServers
// Response: { "servers": [{"name": "firecrawl", "type": "stdio", ...}] }
\`\`\`
**Step 2: List tools**
\`\`\`json
// Call: listMcpTools with serverName: "firecrawl"
// Response: { "tools": [{"name": "firecrawl_search", "description": "Search the web", "inputSchema": {...}}] }
\`\`\`
**Step 3: Execute the tool**
\`\`\`json
{
"serverName": "firecrawl",
"toolName": "firecrawl_search",
"arguments": {
"query": "latest AI news",
"limit": 5
}
}
\`\`\`
### Example: Using Filesystem Tool
**Execute a filesystem read operation:**
\`\`\`json
{
"serverName": "filesystem",
"toolName": "read_file",
"arguments": {
"path": "/path/to/file.txt"
}
}
\`\`\`
### Tips for Executing MCP Tools
- Always check the \`inputSchema\` from \`listMcpTools\` to know what arguments are required
- Match argument types exactly (string, number, boolean, object, array)
- Provide helpful context to the user about what the tool is doing
- Handle errors gracefully and suggest alternatives if a tool fails
- For complex tasks, consider creating an agent instead of one-off tool calls
### Discovery Pattern (Recommended)
When a user asks for something that might be accomplished with an MCP tool:
1. **Identify the need**: "You want to search the web? Let me check what MCP tools are available..."
2. **List servers**: Call \`listMcpServers\`
3. **Check for relevant tools**: If you find a relevant server (e.g., "firecrawl" for web search), call \`listMcpTools\`
4. **Execute the tool**: Once you find the right tool and understand its schema, call \`executeMcpTool\`
5. **Present results**: Format and explain the results to the user
### Common MCP Servers and Their Tools
Based on typical configurations, you might find:
- **firecrawl**: Web scraping, search, crawling (\`firecrawl_search\`, \`firecrawl_scrape\`, \`firecrawl_crawl\`)
- **filesystem**: File operations (\`read_file\`, \`write_file\`, \`list_directory\`)
- **github**: GitHub operations (\`create_issue\`, \`create_pr\`, \`search_repositories\`)
- **fetch**: HTTP requests (\`fetch\`, \`post\`)
- **time**: Time/date operations (\`get_current_time\`, \`convert_timezone\`)
Always use \`listMcpServers\` and \`listMcpTools\` to discover what's actually available rather than assuming.
## Adding MCP Tools to Agents
Once an MCP server is configured, add its tools to agent definitions:
### MCP Tool Format in Agent
\`\`\`json
"tools": {
"descriptive_key": {
"type": "mcp",
"name": "actual_tool_name_from_server",
"description": "What the tool does",
"mcpServerName": "server_name_from_config",
"inputSchema": {
"type": "object",
"properties": {
"param1": {"type": "string", "description": "What param1 means"}
},
"required": ["param1"]
}
}
}
\`\`\`
### Tool Schema Rules
- Use \`listMcpTools\` to get the exact \`inputSchema\` from the server
- Copy the schema exactly as provided by the MCP server
- Only include \`"required"\` array if parameters are truly mandatory
- Add descriptions to help the agent understand parameter usage
### Example snippets to reference
- Firecrawl search (required param):
\`\`\`json
"tools": {
"search": {
"type": "mcp",
"name": "firecrawl_search",
"description": "Search the web",
"mcpServerName": "firecrawl",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"limit": {"type": "number", "description": "Number of results"}
},
"required": ["query"]
}
}
}
\`\`\`
- ElevenLabs text-to-speech (no required array):
\`\`\`json
"tools": {
"text_to_speech": {
"type": "mcp",
"name": "text_to_speech",
"description": "Generate audio from text",
"mcpServerName": "elevenLabs",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string"}
}
}
}
}
\`\`\`
## Safety reminders
- ALWAYS use \`addMcpServer\` to configure MCP servers—never manually edit config files
- Only recommend MCP tools that are actually configured (use \`listMcpServers\` first)
- Clarify any missing details (required parameters, server names) before modifying files
- Test server connection with \`listMcpTools\` after adding a new server
- Invalid MCP configs prevent agents from starting—validation is critical
`;
export default skill;
================================================
FILE: apps/cli/src/application/assistant/skills/workflow-authoring/skill.ts
================================================
export const skill = String.raw`
# Agent and Workflow Authoring
Load this skill whenever a user wants to inspect, create, or update agents inside the Rowboat workspace.
## Core Concepts
**IMPORTANT**: In the CLI, there are NO separate "workflow" files. Everything is an agent.
- **All definitions live in \`agents/*.json\`** - there is no separate workflows folder
- Agents configure a model, instructions, and the tools they can use
- Tools can be: builtin (like \`executeCommand\`), MCP integrations, or **other agents**
- **"Workflows" are just agents that orchestrate other agents** by having them as tools
## How multi-agent workflows work
1. **Create an orchestrator agent** that has other agents in its \`tools\`
2. **Run the orchestrator**: \`rowboatx --agent orchestrator_name\`
3. The orchestrator calls other agents as tools when needed
4. Data flows through tool call parameters and responses
## Agent File Schema
Agent files MUST conform to this exact schema. Invalid agents will fail to load.
### Complete Agent Schema
\`\`\`json
{
"name": "string (REQUIRED, must match filename without .json)",
"description": "string (REQUIRED, what this agent does)",
"instructions": "string (REQUIRED, detailed instructions for the agent)",
"model": "string (OPTIONAL, e.g., 'gpt-5.1', 'claude-sonnet-4-5')",
"provider": "string (OPTIONAL, provider alias from models.json)",
"tools": {
"descriptive_key": {
"type": "builtin | mcp | agent (REQUIRED)",
"name": "string (REQUIRED)",
// Additional fields depend on type - see below
}
}
}
\`\`\`
### Required Fields
- \`name\`: Agent identifier (must exactly match the filename without .json)
- \`description\`: Brief description of agent's purpose
- \`instructions\`: Detailed instructions for how the agent should behave
### Optional Fields
- \`model\`: Model to use (defaults to model config if not specified)
- \`provider\`: Provider alias from models.json (optional)
- \`tools\`: Object containing tool definitions (can be empty or omitted)
### Naming Rules
- Agent filename MUST match the \`name\` field exactly
- Example: If \`name\` is "summariser_agent", file must be "summariser_agent.json"
- Use lowercase with underscores for multi-word names
- No spaces or special characters in names
### Agent Format Example
\`\`\`json
{
"name": "agent_name",
"description": "Description of the agent",
"model": "gpt-5.1",
"instructions": "Instructions for the agent",
"tools": {
"descriptive_tool_key": {
"type": "mcp",
"name": "actual_mcp_tool_name",
"description": "What the tool does",
"mcpServerName": "server_name_from_config",
"inputSchema": {
"type": "object",
"properties": {
"param1": {"type": "string", "description": "What the parameter means"}
}
}
}
}
}
\`\`\`
## Tool Types & Schemas
Tools in agents must follow one of three types. Each has specific required fields.
### 1. Builtin Tools
Internal Rowboat tools (executeCommand, file operations, MCP queries, etc.)
**Schema:**
\`\`\`json
{
"type": "builtin",
"name": "tool_name"
}
\`\`\`
**Required fields:**
- \`type\`: Must be "builtin"
- \`name\`: Builtin tool name (e.g., "executeCommand", "readFile")
**Example:**
\`\`\`json
"bash": {
"type": "builtin",
"name": "executeCommand"
}
\`\`\`
**Available builtin tools:**
- \`executeCommand\` - Execute shell commands
- \`readFile\`, \`createFile\`, \`updateFile\`, \`deleteFile\` - File operations
- \`listFiles\`, \`exploreDirectory\` - Directory operations
- \`analyzeAgent\` - Analyze agent structure
- \`addMcpServer\`, \`listMcpServers\`, \`listMcpTools\` - MCP management
- \`loadSkill\` - Load skill guidance
### 2. MCP Tools
Tools from external MCP servers (APIs, databases, web scraping, etc.)
**Schema:**
\`\`\`json
{
"type": "mcp",
"name": "tool_name_from_server",
"description": "What the tool does",
"mcpServerName": "server_name_from_config",
"inputSchema": {
"type": "object",
"properties": {
"param": {"type": "string", "description": "Parameter description"}
},
"required": ["param"]
}
}
\`\`\`
**Required fields:**
- \`type\`: Must be "mcp"
- \`name\`: Exact tool name from MCP server
- \`description\`: What the tool does (helps agent understand when to use it)
- \`mcpServerName\`: Server name from config/mcp.json
- \`inputSchema\`: Full JSON Schema object for tool parameters
**Example:**
\`\`\`json
"search": {
"type": "mcp",
"name": "firecrawl_search",
"description": "Search the web",
"mcpServerName": "firecrawl",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
}
\`\`\`
**Important:**
- Use \`listMcpTools\` to get the exact inputSchema from the server
- Copy the schema exactly—don't modify property types or structure
- Only include \`"required"\` array if parameters are mandatory
### 3. Agent Tools (for chaining agents)
Reference other agents as tools to build multi-agent workflows
**Schema:**
\`\`\`json
{
"type": "agent",
"name": "target_agent_name"
}
\`\`\`
**Required fields:**
- \`type\`: Must be "agent"
- \`name\`: Name of the target agent (must exist in agents/ directory)
**Example:**
\`\`\`json
"summariser": {
"type": "agent",
"name": "summariser_agent"
}
\`\`\`
**How it works:**
- Use \`"type": "agent"\` to call other agents as tools
- The target agent will be invoked with the parameters you pass
- Results are returned as tool output
- This is how you build multi-agent workflows
- The referenced agent file must exist (e.g., agents/summariser_agent.json)
## Complete Multi-Agent Workflow Example
**Podcast creation workflow** - This is all done through agents calling other agents:
**1. Task-specific agent** (does one thing):
\`\`\`json
{
"name": "summariser_agent",
"description": "Summarises an arxiv paper",
"model": "gpt-5.1",
"instructions": "Download and summarise an arxiv paper. Use curl to fetch the PDF. Output just the GIST in two lines. Don't ask for human input.",
"tools": {
"bash": {"type": "builtin", "name": "executeCommand"}
}
}
\`\`\`
**2. Agent that delegates to other agents**:
\`\`\`json
{
"name": "summarise-a-few",
"description": "Summarises multiple arxiv papers",
"model": "gpt-5.1",
"instructions": "Pick 2 interesting papers and summarise each using the summariser tool. Pass the paper URL to the tool. Don't ask for human input.",
"tools": {
"summariser": {
"type": "agent",
"name": "summariser_agent"
}
}
}
\`\`\`
**3. Orchestrator agent** (coordinates the whole workflow):
\`\`\`json
{
"name": "podcast_workflow",
"description": "Create a podcast from arXiv papers",
"model": "gpt-5.1",
"instructions": "1. Fetch arXiv papers about agents using bash\n2. Pick papers and summarise them using summarise_papers\n3. Create a podcast transcript\n4. Generate audio using text_to_speech\n\nExecute these steps in sequence.",
"tools": {
"bash": {"type": "builtin", "name": "executeCommand"},
"summarise_papers": {
"type": "agent",
"name": "summarise-a-few"
},
"text_to_speech": {
"type": "mcp",
"name": "text_to_speech",
"mcpServerName": "elevenLabs",
"description": "Generate audio",
"inputSchema": { "type": "object", "properties": {...}}
}
}
}
\`\`\`
**To run this workflow**: \`rowboatx --agent podcast_workflow\`
## Naming and organization rules
- **All agents live in \`agents/*.json\`** - no other location
- Agent filenames must match the \`"name"\` field exactly
- When referencing an agent as a tool, use its \`"name"\` value
- Always keep filenames and \`"name"\` fields perfectly aligned
- Use relative paths (no \${BASE_DIR} prefixes) when giving examples to users
## Best practices for multi-agent design
1. **Single responsibility**: Each agent should do one specific thing well
2. **Clear delegation**: Agent instructions should explicitly say when to call other agents
3. **Autonomous operation**: Add "Don't ask for human input" for autonomous workflows
4. **Data passing**: Make it clear what data to extract and pass between agents
5. **Tool naming**: Use descriptive tool keys (e.g., "summariser", "fetch_data", "analyze")
6. **Orchestration**: Create a top-level agent that coordinates the workflow
## Validation & Best Practices
### CRITICAL: Schema Compliance
- Agent files MUST have \`name\`, \`description\`, and \`instructions\` fields
- Agent filename MUST exactly match the \`name\` field
- Tools MUST have valid \`type\` ("builtin", "mcp", or "agent")
- MCP tools MUST have all required fields: name, description, mcpServerName, inputSchema
- Agent tools MUST reference existing agent files
- Invalid agents will fail to load and prevent workflow execution
### File Creation/Update Process
1. When creating an agent, use \`createFile\` with complete, valid JSON
2. When updating an agent, read it first with \`readFile\`, modify, then use \`updateFile\`
3. Validate JSON syntax before writing—malformed JSON breaks the agent
4. Test agent loading after creation/update by using \`analyzeAgent\`
### Common Validation Errors to Avoid
❌ **WRONG - Missing required fields:**
\`\`\`json
{
"name": "my_agent"
// Missing description and instructions
}
\`\`\`
❌ **WRONG - Filename mismatch:**
- File: agents/my_agent.json
- Content: {"name": "myagent", ...}
❌ **WRONG - Invalid tool type:**
\`\`\`json
"tool1": {
"type": "custom", // Invalid type
"name": "something"
}
\`\`\`
❌ **WRONG - MCP tool missing required fields:**
\`\`\`json
"search": {
"type": "mcp",
"name": "firecrawl_search"
// Missing: description, mcpServerName, inputSchema
}
\`\`\`
✅ **CORRECT - Minimal valid agent:**
\`\`\`json
{
"name": "simple_agent",
"description": "A simple agent",
"instructions": "Do simple tasks"
}
\`\`\`
✅ **CORRECT - Complete MCP tool:**
\`\`\`json
"search": {
"type": "mcp",
"name": "firecrawl_search",
"description": "Search the web",
"mcpServerName": "firecrawl",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string"}
}
}
}
\`\`\`
## Capabilities checklist
1. Explore \`agents/\` directory to understand existing agents before editing
2. Read existing agents with \`readFile\` before making changes
3. Validate all required fields are present before creating/updating agents
4. Ensure filename matches the \`name\` field exactly
5. Use \`analyzeAgent\` to verify agent structure after creation/update
6. When creating multi-agent workflows, create an orchestrator agent
7. Add other agents as tools with \`"type": "agent"\` for chaining
8. Use \`listMcpServers\` and \`listMcpTools\` when adding MCP integrations
9. Confirm work done and outline next steps once changes are complete
`;
export default skill;
================================================
FILE: apps/cli/src/application/assistant/skills/workflow-run-ops/skill.ts
================================================
export const skill = String.raw`
# Agent Run Operations
Package of repeatable commands for running agents, inspecting agent run history under ~/.rowboat/runs, and managing cron schedules. Load this skill whenever a user asks about running agents, execution history, paused runs, or scheduling.
## When to use
- User wants to run an agent (including multi-agent workflows)
- User wants to list or filter agent runs (all runs, by agent, time range, or paused for input)
- User wants to inspect cron jobs or change agent schedules
- User asks how to set up monitoring for waiting runs
## Running Agents
**To run any agent**:
\`\`\`bash
rowboatx --agent <agent-name>
\`\`\`
**With input**:
\`\`\`bash
rowboatx --agent <agent-name> --input "your input here"
\`\`\`
**Non-interactive** (for automation/cron):
\`\`\`bash
rowboatx --agent <agent-name> --input "input" --no-interactive
\`\`\`
**Note**: Multi-agent workflows are just agents that have other agents in their tools. Run the orchestrator agent to trigger the whole workflow.
## Run monitoring examples
Operate from ~/.rowboat (Rowboat tools already set this as the working directory). Use executeCommand with the sample Bash snippets below, modifying placeholders as needed.
Each run file name starts with a timestamp like '2025-11-12T08-02-41Z'. You can use this to filter for date/time ranges.
Each line of the run file contains a running log with the first line containing information about the agent run. E.g. '{"type":"start","runId":"2025-11-12T08-02-41Z-0014322-000","agent":"agent_name","interactive":true,"ts":"2025-11-12T08:02:41.168Z"}'
If a run is waiting for human input the last line will contain 'paused_for_human_input'. See examples below.
1. **List all runs**
ls ~/.rowboat/runs
2. **Filter by agent**
grep -rl '"agent":"<agent-name>"' ~/.rowboat/runs | xargs -n1 basename | sed 's/\.jsonl$//' | sort -r
Replace <agent-name> with the desired agent name.
3. **Filter by time window**
To the previous commands add the below through unix pipe
awk -F'/' '$NF >= "2025-11-12T08-03" && $NF <= "2025-11-12T08-10"'
Use the correct timestamps.
4. **Show runs waiting for human input**
awk 'FNR==1{if (NR>1) print fn, last; fn=FILENAME} {last=$0} END{print fn, last}' ~/.rowboat/runs/*.jsonl | grep 'pause-for-human-input' | awk '{print $1}'
Prints the files whose last line equals 'pause-for-human-input'.
## Cron management examples
For scheduling agents to run automatically at specific times.
1. **View current cron schedule**
\`\`\`bash
crontab -l 2>/dev/null || echo 'No crontab entries configured.'
\`\`\`
2. **Schedule an agent to run periodically**
\`\`\`bash
(crontab -l 2>/dev/null; echo '0 10 * * * cd /path/to/cli && rowboatx --agent <agent-name> --input "input" --no-interactive >> ~/.rowboat/logs/<agent-name>.log 2>&1') | crontab -
\`\`\`
Example (runs daily at 10 AM):
\`\`\`bash
(crontab -l 2>/dev/null; echo '0 10 * * * cd ~/rowboat-V2/apps/cli && rowboatx --agent podcast_workflow --no-interactive >> ~/.rowboat/logs/podcast.log 2>&1') | crontab -
\`\`\`
3. **Unschedule/remove an agent**
\`\`\`bash
crontab -l | grep -v '<agent-name>' | crontab -
\`\`\`
## Common cron schedule patterns
- \`0 10 * * *\` - Daily at 10 AM
- \`0 */6 * * *\` - Every 6 hours
- \`0 9 * * 1\` - Every Monday at 9 AM
- \`*/30 * * * *\` - Every 30 minutes
`;
export default skill;
================================================
FILE: apps/cli/src/application/lib/builtin-tools.ts
================================================
import { z, ZodType } from "zod";
import * as fs from "fs/promises";
import * as path from "path";
import { WorkDir as BASE_DIR } from "../../config/config.js";
import { executeCommand } from "./command-executor.js";
import { resolveSkill, availableSkills } from "../assistant/skills/index.js";
import { executeTool, listServers, listTools } from "../../mcp/mcp.js";
import container from "../../di/container.js";
import { IMcpConfigRepo } from "../..//mcp/repo.js";
import { McpServerDefinition } from "../../mcp/schema.js";
const BuiltinToolsSchema = z.record(z.string(), z.object({
description: z.string(),
inputSchema: z.custom<ZodType>(),
execute: z.function({
input: z.any(),
output: z.promise(z.any()),
}),
}));
export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
loadSkill: {
description: "Load a Rowboat skill definition into context by fetching its guidance string",
inputSchema: z.object({
skillName: z.string().describe("Skill identifier or path (e.g., 'workflow-run-ops' or 'src/application/assistant/skills/workflow-run-ops/skill.ts')"),
}),
execute: async ({ skillName }: { skillName: string }) => {
const resolved = resolveSkill(skillName);
if (!resolved) {
return {
success: false,
message: `Skill '${skillName}' not found. Available skills: ${availableSkills.join(", ")}`,
};
}
return {
success: true,
skillName: resolved.id,
path: resolved.catalogPath,
content: resolved.content,
};
},
},
exploreDirectory: {
description: 'Recursively explore directory structure to understand existing agents and file organization',
inputSchema: z.object({
subdirectory: z.string().optional().describe('Subdirectory to explore (optional, defaults to root)'),
maxDepth: z.number().optional().describe('Maximum depth to traverse (default: 3)'),
}),
execute: async ({ subdirectory, maxDepth = 3 }: { subdirectory?: string, maxDepth?: number }) => {
async function explore(dir: string, depth: number = 0): Promise<any> {
if (depth > maxDepth) return null;
try {
const entries = await fs.readdir(dir, { withFileTypes: true });
const result: any = { files: [], directories: {} };
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isFile()) {
const ext = path.extname(entry.name);
const size = (await fs.stat(fullPath)).size;
result.files.push({
name: entry.name,
type: ext || 'no-extension',
size: size,
relativePath: path.relative(BASE_DIR, fullPath),
});
} else if (entry.isDirectory()) {
result.directories[entry.name] = await explore(fullPath, depth + 1);
}
}
return result;
} catch (error) {
return { error: error instanceof Error ? error.message : 'Unknown error' };
}
}
const dirPath = subdirectory ? path.join(BASE_DIR, subdirectory) : BASE_DIR;
const structure = await explore(dirPath);
return {
success: true,
basePath: path.relative(BASE_DIR, dirPath) || '.',
structure,
};
},
},
readFile: {
description: 'Read and parse file contents. For JSON files, provides parsed structure.',
inputSchema: z.object({
filename: z.string().describe('The name of the file to read (relative to .rowboat directory)'),
}),
execute: async ({ filename }: { filename: string }) => {
try {
const filePath = path.join(BASE_DIR, filename);
const content = await fs.readFile(filePath, 'utf-8');
let parsed = null;
let fileType = path.extname(filename);
if (fileType === '.json') {
try {
parsed = JSON.parse(content);
} catch {
parsed = { error: 'Invalid JSON' };
}
}
return {
success: true,
filename,
fileType,
content,
parsed,
path: filePath,
size: content.length,
};
} catch (error) {
return {
success: false,
message: `Failed to read file: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
createFile: {
description: 'Create a new file with content. Automatically creates parent directories if needed.',
inputSchema: z.object({
filename: z.string().describe('The name of the file to create (relative to .rowboat directory)'),
content: z.string().describe('The content to write to the file'),
description: z.string().optional().describe('Optional description of why this file is being created'),
}),
execute: async ({ filename, content, description }: { filename: string, content: string, description?: string }) => {
try {
const filePath = path.join(BASE_DIR, filename);
const dir = path.dirname(filePath);
// Ensure directory exists
await fs.mkdir(dir, { recursive: true });
// Write file
await fs.writeFile(filePath, content, 'utf-8');
return {
success: true,
message: `File '${filename}' created successfully`,
description: description || 'No description provided',
path: filePath,
size: content.length,
};
} catch (error) {
return {
success: false,
message: `Failed to create file: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
updateFile: {
description: 'Update or overwrite the contents of an existing file',
inputSchema: z.object({
filename: z.string().describe('The name of the file to update (relative to .rowboat directory)'),
content: z.string().describe('The new content to write to the file'),
reason: z.string().optional().describe('Optional reason for the update'),
}),
execute: async ({ filename, content, reason }: { filename: string, content: string, reason?: string }) => {
try {
const filePath = path.join(BASE_DIR, filename);
// Check if file exists
await fs.access(filePath);
// Update file
await fs.writeFile(filePath, content, 'utf-8');
return {
success: true,
message: `File '${filename}' updated successfully`,
reason: reason || 'No reason provided',
path: filePath,
size: content.length,
};
} catch (error) {
return {
success: false,
message: `Failed to update file: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
deleteFile: {
description: 'Delete a file from the .rowboat directory',
inputSchema: z.object({
filename: z.string().describe('The name of the file to delete (relative to .rowboat directory)'),
}),
execute: async ({ filename }: { filename: string }) => {
try {
const filePath = path.join(BASE_DIR, filename);
await fs.unlink(filePath);
return {
success: true,
message: `File '${filename}' deleted successfully`,
path: filePath,
};
} catch (error) {
return {
success: false,
message: `Failed to delete file: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
listFiles: {
description: 'List all files and directories in the .rowboat directory or subdirectory',
inputSchema: z.object({
subdirectory: z.string().optional().describe('Optional subdirectory to list (relative to .rowboat directory)'),
}),
execute: async ({ subdirectory }: { subdirectory?: string }) => {
try {
const dirPath = subdirectory ? path.join(BASE_DIR, subdirectory) : BASE_DIR;
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const files = entries
.filter(entry => entry.isFile())
.map(entry => ({
name: entry.name,
type: path.extname(entry.name) || 'no-extension',
relativePath: path.relative(BASE_DIR, path.join(dirPath, entry.name)),
}));
const directories = entries
.filter(entry => entry.isDirectory())
.map(entry => entry.name);
return {
success: true,
path: dirPath,
relativePath: path.relative(BASE_DIR, dirPath) || '.',
files,
directories,
totalFiles: files.length,
totalDirectories: directories.length,
};
} catch (error) {
return {
success: false,
message: `Failed to list files: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
analyzeAgent: {
description: 'Read and analyze an agent file to understand its structure, tools, and configuration',
inputSchema: z.object({
agentName: z.string().describe('Name of the agent file to analyze (with or without .json extension)'),
}),
execute: async ({ agentName }: { agentName: string }) => {
try {
const filename = agentName.endsWith('.json') ? agentName : `${agentName}.json`;
const filePath = path.join(BASE_DIR, 'agents', filename);
const content = await fs.readFile(filePath, 'utf-8');
const agent = JSON.parse(content);
// Extract key information
const toolsList = agent.tools ? Object.keys(agent.tools) : [];
const agentTools = agent.tools ? Object.entries(agent.tools).map(([key, tool]: [string, any]) => ({
key,
type: tool.type,
name: tool.name || key,
})) : [];
const analysis = {
name: agent.name,
description: agent.description || 'No description',
model: agent.model || 'Not specified',
toolCount: toolsList.length,
tools: agentTools,
hasOtherAgents: agentTools.some((t: any) => t.type === 'agent'),
structure: agent,
};
return {
success: true,
filePath: path.relative(BASE_DIR, filePath),
analysis,
};
} catch (error) {
return {
success: false,
message: `Failed to analyze agent: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
addMcpServer: {
description: 'Add or update an MCP server in the configuration with validation. This ensures the server definition is valid before saving.',
inputSchema: z.object({
serverName: z.string().describe('Name/alias for the MCP server'),
config: McpServerDefinition,
}),
execute: async ({ serverName, config }: {
serverName: string;
config: z.infer<typeof McpServerDefinition>;
}) => {
try {
const validationResult = McpServerDefinition.safeParse(config);
if (!validationResult.success) {
return {
success: false,
message: 'Server definition failed validation. Check the errors below.',
validationErrors: validationResult.error.issues.map((e: any) => `${e.path.join('.')}: ${e.message}`),
providedDefinition: config,
};
}
const repo = container.resolve<IMcpConfigRepo>('mcpConfigRepo');
await repo.upsert(serverName, config);
return {
success: true,
serverName,
};
} catch (error) {
return {
error: `Failed to update MCP server: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
listMcpServers: {
description: 'List all available MCP servers from the configuration',
inputSchema: z.object({}),
execute: async () => {
try {
const result = await listServers();
return {
result,
count: Object.keys(result.mcpServers).length,
};
} catch (error) {
return {
error: `Failed to list MCP servers: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
listMcpTools: {
description: 'List all available tools from a specific MCP server',
inputSchema: z.object({
serverName: z.string().describe('Name of the MCP server to query'),
cursor: z.string().optional(),
}),
execute: async ({ serverName, cursor }: { serverName: string, cursor?: string }) => {
try {
const result = await listTools(serverName, cursor);
return {
serverName,
result,
count: result.tools.length,
};
} catch (error) {
return {
error: `Failed to list MCP tools: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
},
},
executeMcpTool: {
description: 'Execute a specific tool from an MCP server. Use this to run MCP tools on behalf of the user. IMPORTANT: Always use listMcpTools first to get the tool\'s inputSchema, then match the required parameters exactly in the arguments field.',
inputSchema: z.object({
serverName: z.string().describe('Name of the MCP server that provides the tool'),
toolName: z.string().describe('Name of the tool to execute'),
arguments: z.record(z.string(), z.any()).optional().describe('Arguments to pass to the tool (as key-value pairs matching the tool\'s input schema). MUST include all required parameters from the tool\'s inputSchema.'),
}),
execute: async ({ serverName, toolName, arguments: args = {} }: { serverName: string, toolName: string, arguments?: Record<string, any> }) => {
try {
const result = await executeTool(serverName, toolName, args);
return {
success: true,
serverName,
toolName,
result,
message: `Successfully executed tool '${toolName}' from server '${serverName}'`,
};
} catch (error) {
return {
success: false,
error: `Failed to execute MCP tool: ${error instanceof Error ? error.message : 'Unknown error'}`,
hint: 'Use listMcpTools to verify the tool exists and check its schema. Ensure all required parameters are provided in the arguments field.',
};
}
},
},
executeCommand: {
description: 'Execute a shell command and return the output. Use this to run bash/shell commands.',
inputSchema: z.object({
command: z.string().describe('The shell command to execute (e.g., "ls -la", "cat file.txt")'),
cwd: z.string().optional().describe('Working directory to execute the command in (defaults to .rowboat directory)'),
}),
execute: async ({ command, cwd }: { command: string, cwd?: string }) => {
try {
const workingDir = cwd ? path.join(BASE_DIR, cwd) : BASE_DIR;
const result = await executeCommand(command, { cwd: workingDir });
return {
success: result.exitCode === 0,
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode,
command,
workingDir,
};
} catch (error) {
return {
success: false,
message: `Failed to execute command: ${error instanceof Error ? error.message : 'Unknown error'}`,
command,
};
}
},
},
};
================================================
FILE: apps/cli/src/application/lib/bus.ts
================================================
import { RunEvent } from "../../entities/run-events.js";
import z from "zod";
export interface IBus {
publish(event: z.infer<typeof RunEvent>): Promise<void>;
// subscribe accepts a handler to handle events
// and returns a function to unsubscribe
subscribe(runId: string, handler: (event: z.infer<typeof RunEvent>) => Promise<void>): Promise<() => void>;
}
export class InMemoryBus implements IBus {
private subscribers: Map<string, ((event: z.infer<typeof RunEvent>) => Promise<void>)[]> = new Map();
async publish(event: z.infer<typeof RunEvent>): Promise<void> {
const pending: Promise<void>[] = [];
for (const subscriber of this.subscribers.get(event.runId) || []) {
pending.push(subscriber(event));
}
for (const subscriber of this.subscribers.get('*') || []) {
pending.push(subscriber(event));
}
await Promise.all(pending);
}
async subscribe(runId: string, handler: (event: z.infer<typeof RunEvent>) => Promise<void>): Promise<() => void> {
if (!this.subscribers.has(runId)) {
this.subscribers.set(runId, []);
}
this.subscribers.get(runId)!.push(handler);
return () => {
this.subscribers.get(runId)!.splice(this.subscribers.get(runId)!.indexOf(handler), 1);
};
}
}
================================================
FILE: apps/cli/src/application/lib/command-executor.ts
================================================
import { exec, execSync } from 'child_process';
import { promisify } from 'util';
import { getSecurityAllowList, SECURITY_CONFIG_PATH } from '../../config/security.js';
import { getExecutionShell } from '../assistant/runtime-context.js';
const execPromise = promisify(exec);
const COMMAND_SPLIT_REGEX = /(?:\|\||&&|;|\||\n)/;
const ENV_ASSIGNMENT_REGEX = /^[A-Za-z_][A-Za-z0-9_]*=.*/;
const WRAPPER_COMMANDS = new Set(['sudo', 'env', 'time', 'command']);
const EXECUTION_SHELL = getExecutionShell();
function sanitizeToken(token: string): string {
return token.trim().replace(/^['"]+|['"]+$/g, '');
}
function extractCommandNames(command: string): string[] {
const discovered = new Set<string>();
const segments = command.split(COMMAND_SPLIT_REGEX);
for (const segment of segments) {
const tokens = segment.trim().split(/\s+/).filter(Boolean);
if (!tokens.length) continue;
let index = 0;
while (index < tokens.length && ENV_ASSIGNMENT_REGEX.test(tokens[index])) {
index++;
}
if (index >= tokens.length) continue;
const primary = sanitizeToken(tokens[index]).toLowerCase();
if (!primary) continue;
discovered.add(primary);
if (WRAPPER_COMMANDS.has(primary) && index + 1 < tokens.length) {
const wrapped = sanitizeToken(tokens[index + 1]).toLowerCase();
if (wrapped) {
discovered.add(wrapped);
}
}
}
return Array.from(discovered);
}
function findBlockedCommands(command: string): string[] {
const invoked = extractCommandNames(command);
if (!invoked.length) return [];
const allowList = getSecurityAllowList();
if (!allowList.length) return invoked;
const allowSet = new Set(allowList);
if (allowSet.has('*')) return [];
return invoked.filter((cmd) => !allowSet.has(cmd));
}
// export const BlockedResult = {
// stdout: '',
// stderr: `Command blocked by security policy. Update ${SECURITY_CONFIG_PATH} to allow them before retrying.`,
// exitCode: 126,
// };
export function isBlocked(command: string): boolean {
const blocked = findBlockedCommands(command);
return blocked.length > 0;
}
export interface CommandResult {
stdout: string;
stderr: string;
exitCode: number;
}
/**
* Executes an arbitrary shell command
* @param command - The command to execute (e.g., "cat abc.txt | grep 'abc@gmail.com'")
* @param options - Optional execution options
* @returns Promise with stdout, stderr, and exit code
*/
export async function executeCommand(
command: string,
options?: {
cwd?: string;
timeout?: number; // timeout in milliseconds
maxBuffer?: number; // max buffer size in bytes
}
): Promise<CommandResult> {
try {
const { stdout, stderr } = await execPromise(command, {
cwd: options?.cwd,
timeout: options?.timeout,
maxBuffer: options?.maxBuffer || 1024 * 1024, // default 1MB
shell: EXECUTION_SHELL,
});
return {
stdout: stdout.trim(),
stderr: stderr.trim(),
exitCode: 0,
};
} catch (error: any) {
// exec throws an error if the command fails or times out
return {
stdout: error.stdout?.trim() || '',
stderr: error.stderr?.trim() || error.message,
exitCode: error.code || 1,
};
}
}
/**
* Executes a command synchronously (blocking)
* Use with caution - prefer executeCommand for async execution
*/
export function executeCommandSync(
command: string,
options?: {
cwd?: string;
timeout?: number;
}
): CommandResult {
try {
const stdout = execSync(command, {
cwd: options?.cwd,
timeout: options?.timeout,
encoding: 'utf-8',
shell: EXECUTION_SHELL,
});
return {
stdout: stdout.trim(),
stderr: '',
exitCode: 0,
};
} catch (error: any) {
return {
stdout: error.stdout?.toString().trim() || '',
stderr: error.stderr?.toString().trim() || error.message,
exitCode: error.status || 1,
};
}
}
================================================
FILE: apps/cli/src/application/lib/exec-tool.ts
================================================
import { ToolAttachment } from "../../agents/agents.js";
import { z } from "zod";
import { BuiltinTools } from "./builtin-tools.js";
import { executeTool } from "../../mcp/mcp.js";
async function execMcpTool(agentTool: z.infer<typeof ToolAttachment> & { type: "mcp" }, input: any): Promise<any> {
const result = await executeTool(agentTool.mcpServerName, agentTool.name, input);
return result;
}
export async function execTool(agentTool: z.infer<typeof ToolAttachment>, input: any): Promise<any> {
switch (agentTool.type) {
case "mcp":
return execMcpTool(agentTool, input);
case "builtin":
const builtinTool = BuiltinTools[agentTool.name];
if (!builtinTool || !builtinTool.execute) {
throw new Error(`Unsupported builtin tool: ${agentTool.name}`);
}
return builtinTool.execute(input);
}
}
================================================
FILE: apps/cli/src/application/lib/id-gen.ts
================================================
export interface IMonotonicallyIncreasingIdGenerator {
next(): Promise<string>;
}
export class IdGen implements IMonotonicallyIncreasingIdGenerator {
private lastMs = 0;
private seq = 0;
private readonly pid: string;
private readonly hostTag: string;
constructor() {
this.pid = String(process.pid).padStart(7, "0");
this.hostTag = "";
}
/**
* Returns an ISO8601-based, lexicographically sortable id string.
* Example: 2025-11-11T04-36-29Z-0001234-h1-000
*/
async next(): Promise<string> {
const now = Date.now();
const ms = now >= this.lastMs ? now : this.lastMs; // monotonic clamp
this.seq = ms === this.lastMs ? this.seq + 1 : 0;
this.lastMs = ms;
// Build ISO string (UTC) and remove milliseconds for cleaner filenames
const iso = new Date(ms).toISOString() // e.g. 2025-11-11T04:36:29.123Z
.replace(/\.\d{3}Z$/, "Z") // drop .123 part
.replace(/:/g, "-"); // safe for files: 2025-11-11T04-36-29Z
const seqStr = String(this.seq).padStart(3, "0");
return `${iso}-${this.pid}${this.hostTag}-${seqStr}`;
}
}
================================================
FILE: apps/cli/src/application/lib/message-queue.ts
================================================
import z from "zod";
import { IMonotonicallyIncreasingIdGenerator } from "./id-gen.js";
const EnqueuedMessage = z.object({
messageId: z.string(),
message: z.string(),
});
export interface IMessageQueue {
enqueue(runId: string, message: string): Promise<string>;
dequeue(runId: string): Promise<z.infer<typeof EnqueuedMessage> | null>;
}
export class InMemoryMessageQueue implements IMessageQueue {
private store: Record<string, z.infer<typeof EnqueuedMessage>[]> = {};
private idGenerator: IMonotonicallyIncreasingIdGenerator;
constructor({
idGenerator,
}: {
idGenerator: IMonotonicallyIncreasingIdGenerator;
}) {
this.idGenerator = idGenerator;
}
async enqueue(runId: string, message: string): Promise<string> {
if (!this.store[runId]) {
this.store[runId] = [];
}
const id = await this.idGenerator.next();
this.store[runId].push({
messageId: id,
message,
});
return id;
}
async dequeue(runId: string): Promise<z.infer<typeof EnqueuedMessage> | null> {
if (!this.store[runId]) {
return null;
}
return this.store[runId].shift() ?? null;
}
}
================================================
FILE: apps/cli/src/application/lib/random-id.ts
================================================
import { customAlphabet } from 'nanoid';
const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz-';
const nanoid = customAlphabet(alphabet, 7);
export async function randomId(): Promise<string> {
return nanoid();
}
================================================
FILE: apps/cli/src/application/lib/stream-renderer.ts
================================================
import { z } from "zod";
import { RunEvent } from "../../entities/run-events.js";
import { LlmStepStreamEvent } from "../../entities/llm-step-events.js";
export interface StreamRendererOptions {
showHeaders?: boolean;
dimReasoning?: boolean;
jsonIndent?: number;
truncateJsonAt?: number;
}
export class StreamRenderer {
private options: Required<StreamRendererOptions>;
private reasoningActive = false;
private textActive = false;
private firstText = true;
constructor(options?: StreamRendererOptions) {
this.options = {
showHeaders: true,
dimReasoning: true,
jsonIndent: 2,
truncateJsonAt: 500,
...options,
};
}
render(event: z.infer<typeof RunEvent>) {
switch (event.type) {
case "start": {
this.onStart(event.agentName, event.runId);
break;
}
case "llm-stream-event": {
this.renderLlmEvent(event.event);
break;
}
case "message": {
// this.onStepMessage(event.stepId, event.message);
break;
}
case "tool-invocation": {
this.onStepToolInvocation(event.toolName, event.input);
break;
}
case "tool-result": {
this.onStepToolResult(event.toolName, event.result);
break;
}
case "error": {
this.onError(event.error);
break;
}
}
}
private renderLlmEvent(event: z.infer<typeof LlmStepStreamEvent>) {
switch (event.type) {
case "reasoning-start":
this.onReasoningStart();
break;
case "reasoning-delta":
this.onReasoningDelta(event.delta);
break;
case "reasoning-end":
this.onReasoningEnd();
break;
case "text-start":
this.onTextStart();
break;
case "text-delta":
this.onTextDelta(event.delta);
break;
case "text-end":
this.onTextEnd();
break;
case "tool-call":
this.onToolCall(event.toolCallId, event.toolName, event.input);
break;
case "finish-step":
this.onFinishStep(event.finishReason, event.usage);
break;
}
}
private onStart(agentName: string, runId: string) {
this.write("\n");
this.write(this.bold(`▶ Agent ${agentName} (run ${runId})`));
this.write("\n");
this.write(this.dim(`╰─────────────────────────────────────────────────\n`));
}
private onEnd() {
this.write("\n");
this.write(this.dim("─".repeat(50)));
this.write("\n");
this.write(this.green(this.bold("✓ Complete")));
this.write("\n\n");
}
private onError(error: string) {
this.write("\n");
this.write(this.red(this.bold("✖ Error")));
this.write("\n");
this.write(this.red(this.indent(error)));
this.write("\n\n");
}
private onStepStart() {
this.write("\n");
this.write(this.dim("│ "));
this.write(this.dim("Step in progress..."));
this.write("\n");
}
private onStepEnd() {
// More subtle step end - just add a little spacing
this.write(this.dim("\n"));
}
private onStepMessage(stepIndex: number, message: any) {
const role = message?.role ?? "message";
const content = message?.content;
this.write(this.bold(`${role}: `));
if (typeof content === "string") {
this.write(content + "\n");
} else {
const pretty = this.truncate(JSON.stringify(message, null, this.options.jsonIndent));
this.write(this.dim("\n" + this.indent(pretty) + "\n"));
}
}
private onStepToolInvocation(toolName: string, input: string) {
this.write("\n");
this.write(this.cyan("┌─ ") + this.bold(this.cyan(`🔧 ${toolName}`)));
this.write("\n");
if (input && input.length) {
this.write(this.dim("│ ") + this.dim(this.indent(this.truncate(input)).replace(/\n/g, "\n│ ")));
this.write("\n");
}
}
private onStepToolResult(toolName: string, result: unknown) {
const res = this.truncate(JSON.stringify(result, null, this.options.jsonIndent));
this.write(this.dim("│\n"));
this.write(this.green("└─ ") + this.dim(this.green(`Result`)));
this.write("\n");
this.write(this.dim(" " + this.indent(res).replace(/\n/g, "\n ")));
this.write("\n");
}
private onReasoningStart() {
if (this.reasoningActive) return;
this.reasoningActive = true;
if (this.options.showHeaders) {
this.write("\n");
this.write(this.dim("│ "));
this.write(this.dim(this.italic("thinking... ")));
}
}
private onReasoningDelta(delta: string) {
if (!this.reasoningActive) this.onReasoningStart();
this.write(this.options.dimReasoning ? this.dim(delta) : delta);
}
private onReasoningEnd() {
if (!this.reasoningActive) return;
this.reasoningActive = false;
this.write("\n");
}
private onTextStart() {
if (this.textActive) return;
this.textActive = true;
if (this.options.showHeaders && this.firstText) {
this.write("\n");
this.write(this.bold("╭─ ") + this.bold("Response"));
this.write("\n");
this.write(this.dim("│\n"));
this.firstText = false;
} else if (this.options.showHeaders) {
this.write("\n");
this.write(this.dim("│ "));
}
}
private onTextDelta(delta: string) {
// Add subtle left margin to assistant text for better readability
const formattedDelta = this.neutral(delta);
if (delta.includes("\n")) {
this.write(formattedDelta.replace(/\n/g, "\n "));
} else {
this.write(formattedDelta);
}
}
private onTextEnd() {
if (!this.textActive) return;
this.textActive = false;
this.write("\n");
}
private onToolCall(toolCallId: string, toolName: string, input: unknown) {
const inputStr = this.truncate(JSON.stringify(input, null, this.options.jsonIndent));
this.write("\n");
this.write(this.magenta("┌─ ") + this.bold(this.magenta(`⚡ ${toolName}`)));
this.write(this.dim(` (${toolCallId.slice(0, 8)}...)`));
this.write("\n");
this.write(this.dim("│ ") + this.dim(this.indent(inputStr).replace(/\n/g, "\n│ ")));
this.write("\n");
this.write(this.dim("└─────────────\n"));
}
private onPauseForHumanInput(toolCallId: string, question: string) {
this.write(this.cyan(`\n→ Pause for human input (${toolCallId})`));
this.write("\n");
this.write(this.bold("Question: ") + question);
this.write("\n");
}
private onFinishStep(
finishReason: "stop" | "tool-calls" | "length" | "content-filter" | "error" | "other" | "unknown",
usage: {
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
reasoningTokens?: number;
cachedInputTokens?: number;
}) {
const parts: string[] = [];
if (usage.inputTokens !== undefined) parts.push(`${this.dim("in:")} ${usage.inputTokens}`);
if (usage.outputTokens !== undefined) parts.push(`${this.dim("out:")} ${usage.outputTokens}`);
if (usage.reasoningTokens !== undefined) parts.push(`${this.dim("reasoning:")} ${usage.reasoningTokens}`);
if (usage.cachedInputTokens !== undefined) parts.push(`${this.dim("cached:")} ${usage.cachedInputTokens}`);
if (usage.totalTokens !== undefined) parts.push(`${this.dim("total:")} ${this.bold(usage.totalTokens.toString())}`);
const line = parts.join(this.dim(" | "));
this.write("\n");
this.write(this.bold("╭─ ") + this.bold("Finish"));
this.write("\n");
this.write(this.dim("│ ") + this.dim("reason: ") + finishReason);
if (line.length) {
this.write("\n");
this.write(this.dim("│ ") + line);
}
this.write("\n");
this.write(this.dim("╰─────────────\n"));
}
// Formatting helpers
private write(text: string) {
process.stdout.write(text);
}
private indent(text: string): string {
return text
.split("\n")
.map((line) => (line.length ? ` ${line}` : line))
.join("\n");
}
private truncate(text: string): string {
if (text.length <= this.options.truncateJsonAt) return text;
return text.slice(0, this.options.truncateJsonAt) + "…";
}
private bold(text: string): string {
return "\x1b[1m" + text + "\x1b[0m";
}
private dim(text: string): string {
return "\x1b[2m" + text + "\x1b[0m";
}
private italic(text: string): string {
return "\x1b[3m" + text + "\x1b[0m";
}
private cyan(text: string): string {
return "\x1b[36m" + text + "\x1b[0m";
}
private green(text: string): string {
return "\x1b[32m" + text + "\x1b[0m";
}
private red(text: string): string {
return "\x1b[31m" + text + "\x1b[0m";
}
private magenta(text: string): string {
return "\x1b[35m" + text + "\x1b[0m";
}
private yellow(text: string): string {
return "\x1b[33m" + text + "\x1b[0m";
}
private neutral(text: string): string {
return "\x1b[38;5;250m" + text + "\x1b[0m";
}
}
================================================
FILE: apps/cli/src/config/config.ts
================================================
import path from "path";
import fs from "fs";
import { homedir } from "os";
// Resolve app root relative to compiled file location (dist/...)
export const WorkDir = path.join(homedir(), ".rowboat");
function ensureDirs() {
const ensure = (p: string) => { if (!fs.existsSync(p)) fs.mkdirSync(p, { recursive: true }); };
ensure(WorkDir);
ensure(path.join(WorkDir, "agents"));
ensure(path.join(WorkDir, "config"));
}
ensureDirs();
================================================
FILE: apps/cli/src/config/security.ts
================================================
import path from "path";
import fs from "fs";
import { WorkDir } from "./config.js";
export const SECURITY_CONFIG_PATH = path.join(WorkDir, "config", "security.json");
const DEFAULT_ALLOW_LIST = [
"cat",
"curl",
"date",
"echo",
"grep",
"jq",
"ls",
"pwd",
"yq",
"whoami"
]
let cachedAllowList: string[] | null = null;
let cachedMtimeMs: number | null = null;
function ensureSecurityConfig() {
if (!fs.existsSync(SECURITY_CONFIG_PATH)) {
fs.writeFileSync(
SECURITY_CONFIG_PATH,
JSON.stringify(DEFAULT_ALLOW_LIST, null, 2) + "\n",
"utf8",
);
}
}
function normalizeList(commands: unknown[]): string[] {
const seen = new Set<string>();
for (const entry of commands) {
if (typeof entry !== "string") continue;
const normalized = entry.trim().toLowerCase();
if (!normalized) continue;
seen.add(normalized);
}
return Array.from(seen);
}
function parseSecurityPayload(payload: unknown): string[] {
if (Array.isArray(payload)) {
return normalizeList(payload);
}
if (payload && typeof payload === "object") {
const maybeObject = payload as Record<string, unknown>;
if (Array.isArray(maybeObject.allowedCommands)) {
return normalizeList(maybeObject.allowedCommands);
}
const dynamicList = Object.entries(maybeObject)
.filter(([, value]) => Boolean(value))
.map(([key]) => key);
return normalizeList(dynamicList);
}
return [];
}
function readAllowList(): string[] {
ensureSecurityConfig();
try {
const configContent = fs.readFileSync(SECURITY_CONFIG_PATH, "utf8");
const parsed = JSON.parse(configContent);
return parseSecurityPayload(parsed);
} catch (error) {
console.warn(`Failed to read security config at ${SECURITY_CONFIG_PATH}: ${error instanceof Error ? error.message : error}`);
return DEFAULT_ALLOW_LIST;
}
}
export function getSecurityAllowList(): string[] {
ensureSecurityConfig();
try {
const stats = fs.statSync(SECURITY_CONFIG_PATH);
if (cachedAllowList && cachedMtimeMs === stats.mtimeMs) {
return cachedAllowList;
}
const allowList = readAllowList();
cachedAllowList = allowList;
cachedMtimeMs = stats.mtimeMs;
return allowList;
} catch {
cachedAllowList = null;
cachedMtimeMs = null;
return readAllowList();
}
}
export function resetSecurityAllowListCache() {
cachedAllowList = null;
cachedMtimeMs = null;
}
================================================
FILE: apps/cli/src/di/container.ts
================================================
import { asClass, createContainer, InjectionMode } from "awilix";
import { FSModelConfigRepo, IModelConfigRepo } from "../models/repo.js";
import { FSMcpConfigRepo, IMcpConfigRepo } from "../mcp/repo.js";
import { FSAgentsRepo, IAgentsRepo } from "../agents/repo.js";
import { FSRunsRepo, IRunsRepo } from "../runs/repo.js";
import { IMonotonicallyIncreasingIdGenerator, IdGen } from "../application/lib/id-gen.js";
import { IMessageQueue, InMemoryMessageQueue } from "../application/lib/message-queue.js";
import { IBus, InMemoryBus } from "../application/lib/bus.js";
import { IRunsLock, InMemoryRunsLock } from "../runs/lock.js";
import { IAgentRuntime, AgentRuntime } from "../agents/runtime.js";
const container = createContainer({
injectionMode: InjectionMode.PROXY,
strict: true,
});
container.register({
idGenerator: asClass<IMonotonicallyIncreasingIdGenerator>(IdGen).singleton(),
messageQueue: asClass<IMessageQueue>(InMemoryMessageQueue).singleton(),
bus: asClass<IBus>(InMemoryBus).singleton(),
runsLock: asClass<IRunsLock>(InMemoryRunsLock).singleton(),
agentRuntime: asClass<IAgentRuntime>(AgentRuntime).singleton(),
mcpConfigRepo: asClass<IMcpConfigRepo>(FSMcpConfigRepo).singleton(),
modelConfigRepo: asClass<IModelConfigRepo>(FSModelConfigRepo).singleton(),
agentsRepo: asClass<IAgentsRepo>(FSAgentsRepo).singleton(),
runsRepo: asClass<IRunsRepo>(FSRunsRepo).singleton(),
});
export default container;
================================================
FILE: apps/cli/src/entities/example.ts
================================================
import z from "zod"
import { Agent } from "../agents/agents.js"
import { McpServerDefinition } from "../mcp/schema.js";
export const Example = z.object({
id: z.string(),
instructions: z.string().optional(),
description: z.string().optional(),
entryAgent: z.string().optional(),
agents: z.array(Agent).optional(),
mcpServers: z.record(z.string(), McpServerDefinition).optional(),
});
================================================
FILE: apps/cli/src/entities/llm-step-events.ts
================================================
import { z } from "zod";
import { ProviderOptions } from "./message.js";
const BaseEvent = z.object({
providerOptions: ProviderOptions.optional(),
})
export const LlmStepStreamReasoningStartEvent = BaseEvent.extend({
type: z.literal("reasoning-start"),
});
export const LlmStepStreamReasoningDeltaEvent = BaseEvent.extend({
type: z.literal("reasoning-delta"),
delta: z.string(),
});
export const LlmStepStreamReasoningEndEvent = BaseEvent.extend({
type: z.literal("reasoning-end"),
});
export const LlmStepStreamTextStartEvent = BaseEvent.extend({
type: z.literal("text-start"),
});
export const LlmStepStreamTextDeltaEvent = BaseEvent.extend({
type: z.literal("text-delta"),
delta: z.string(),
});
export const LlmStepStreamTextEndEvent = BaseEvent.extend({
type: z.literal("text-end"),
});
export const LlmStepStreamToolCallEvent = BaseEvent.extend({
type: z.literal("tool-call"),
toolCallId: z.string(),
toolName: z.string(),
input: z.any(),
});
export const LlmStepStreamFinishStepEvent = z.object({
type: z.literal("finish-step"),
finishReason: z.enum(["stop", "tool-calls", "length", "content-filter", "error", "other", "unknown"]),
usage: z.object({
inputTokens: z.number().optional(),
outputTokens: z.number().optional(),
totalTokens: z.number().optional(),
reasoningTokens: z.number().optional(),
cachedInputTokens: z.number().optional(),
}),
providerOptions: ProviderOptions.optional(),
});
export const LlmStepStreamEvent = z.union([
LlmStepStreamReasoningStartEvent,
LlmStepStreamReasoningDeltaEvent,
LlmStepStreamReasoningEndEvent,
LlmStepStreamTextStartEvent,
LlmStepStreamTextDeltaEvent,
LlmStepStreamTextEndEvent,
LlmStepStreamToolCallEvent,
LlmStepStreamFinishStepEvent,
]);
================================================
FILE: apps/cli/src/entities/message.ts
================================================
import { z } from "zod";
export const ProviderOptions = z.record(z.string(), z.record(z.string(), z.json()));
export const TextPart = z.object({
type: z.literal("text"),
text: z.string(),
providerOptions: ProviderOptions.optional(),
});
export const ReasoningPart = z.object({
type: z.literal("reasoning"),
text: z.string(),
providerOptions: ProviderOptions.optional(),
});
export const ToolCallPart = z.object({
type: z.literal("tool-call"),
toolCallId: z.string(),
toolName: z.string(),
arguments: z.any(),
providerOptions: ProviderOptions.optional(),
});
export const AssistantContentPart = z.union([
TextPart,
ReasoningPart,
ToolCallPart,
]);
export const UserMessage = z.object({
role: z.literal("user"),
content: z.string(),
providerOptions: ProviderOptions.optional(),
});
export const AssistantMessage = z.object({
role: z.literal("assistant"),
content: z.union([
z.string(),
z.array(AssistantContentPart),
]),
providerOptions: ProviderOptions.optional(),
});
export const SystemMessage = z.object({
role: z.literal("system"),
content: z.string(),
providerOptions: ProviderOptions.optional(),
});
export const ToolMessage = z.object({
role: z.literal("tool"),
content: z.string(),
toolCallId: z.string(),
toolName: z.string(),
providerOptions: ProviderOptions.optional(),
});
export const Message = z.discriminatedUnion("role", [
AssistantMessage,
SystemMessage,
ToolMessage,
UserMessage,
]);
export const MessageList = z.array(Message);
================================================
FILE: apps/cli/src/entities/run-events.ts
================================================
import { LlmStepStreamEvent } from "./llm-step-events.js";
import { Message, ToolCallPart } from "./message.js";
import z from "zod";
const BaseRunEvent = z.object({
runId: z.string(),
ts: z.iso.datetime().optional(),
subflow: z.array(z.string()),
});
export const RunProcessingStartEvent = BaseRunEvent.extend({
type: z.literal("run-processing-start"),
});
export const RunProcessingEndEvent = BaseRunEvent.extend({
type: z.literal("run-processing-end"),
});
export const StartEvent = BaseRunEvent.extend({
type: z.literal("start"),
agentName: z.string(),
});
export const SpawnSubFlowEvent = BaseRunEvent.extend({
type: z.literal("spawn-subflow"),
agentName: z.string(),
toolCallId: z.string(),
});
export const LlmStreamEvent = BaseRunEvent.extend({
type: z.literal("llm-stream-event"),
event: LlmStepStreamEvent,
});
export const MessageEvent = BaseRunEvent.extend({
type: z.literal("message"),
messageId: z.string(),
message: Message,
});
export const ToolInvocationEvent = BaseRunEvent.extend({
type: z.literal("tool-invocation"),
toolCallId: z.string().optional(),
toolName: z.string(),
input: z.string(),
});
export const ToolResultEvent = BaseRunEvent.extend({
type: z.literal("tool-result"),
toolCallId: z.string().optional(),
toolName: z.string(),
result: z.any(),
});
export const AskHumanRequestEvent = BaseRunEvent.extend({
type: z.literal("ask-human-request"),
toolCallId: z.string(),
query: z.string(),
});
export const AskHumanResponseEvent = BaseRunEvent.extend({
type: z.literal("ask-human-response"),
toolCallId: z.string(),
response: z.string(),
});
export const ToolPermissionRequestEvent = BaseRunEvent.extend({
type: z.literal("tool-permission-request"),
toolCall: ToolCallPart,
});
export const ToolPermissionResponseEvent = BaseRunEvent.extend({
type: z.literal("tool-permission-response"),
toolCallId: z.string(),
response: z.enum(["approve", "deny"]),
});
export const RunErrorEvent = BaseRunEvent.extend({
type: z.literal("error"),
error: z.string(),
});
export const RunEvent = z.union([
RunProcessingStartEvent,
RunProcessingEndEvent,
StartEvent,
SpawnSubFlowEvent,
LlmStreamEvent,
MessageEvent,
ToolInvocationEvent,
ToolResultEvent,
AskHumanRequestEvent,
AskHumanResponseEvent,
ToolPermissionRequestEvent,
ToolPermissionResponseEvent,
RunErrorEvent,
]);
================================================
FILE: apps/cli/src/examples/index.ts
================================================
import twitterPodcast from './twitter-podcast.json' with { type: 'json' };
import { Example } from '../entities/example.js';
import z from 'zod';
export const examples: Record<string, z.infer<typeof Example>> = {
"twitter-podcast": Example.parse(twitterPodcast),
};
================================================
FILE: apps/cli/src/examples/twitter-podcast.json
================================================
{
"id": "twitter-podcast",
"instructions": "This example workflow generates a narrated podcast episode
gitextract_kg5bbks8/ ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── electron-build.yml │ ├── rowboat-build.yml │ └── x-publish.yml ├── .gitignore ├── CLAUDE.md ├── Dockerfile.qdrant ├── LICENSE ├── README.md ├── apps/ │ ├── cli/ │ │ ├── .gitignore │ │ ├── bin/ │ │ │ └── app.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── agents/ │ │ │ │ ├── agents.ts │ │ │ │ ├── repo.ts │ │ │ │ └── runtime.ts │ │ │ ├── app.ts │ │ │ ├── application/ │ │ │ │ ├── assistant/ │ │ │ │ │ ├── agent.ts │ │ │ │ │ ├── instructions.ts │ │ │ │ │ ├── runtime-context.ts │ │ │ │ │ └── skills/ │ │ │ │ │ ├── builtin-tools/ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ ├── deletion-guardrails/ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── mcp-integration/ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ ├── workflow-authoring/ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ └── workflow-run-ops/ │ │ │ │ │ └── skill.ts │ │ │ │ └── lib/ │ │ │ │ ├── builtin-tools.ts │ │ │ │ ├── bus.ts │ │ │ │ ├── command-executor.ts │ │ │ │ ├── exec-tool.ts │ │ │ │ ├── id-gen.ts │ │ │ │ ├── message-queue.ts │ │ │ │ ├── random-id.ts │ │ │ │ └── stream-renderer.ts │ │ │ ├── config/ │ │ │ │ ├── config.ts │ │ │ │ └── security.ts │ │ │ ├── di/ │ │ │ │ └── container.ts │ │ │ ├── entities/ │ │ │ │ ├── example.ts │ │ │ │ ├── llm-step-events.ts │ │ │ │ ├── message.ts │ │ │ │ └── run-events.ts │ │ │ ├── examples/ │ │ │ │ ├── index.ts │ │ │ │ └── twitter-podcast.json │ │ │ ├── knowledge/ │ │ │ │ ├── sync_calendar.ts │ │ │ │ └── sync_gmail.ts │ │ │ ├── mcp/ │ │ │ │ ├── mcp.ts │ │ │ │ ├── repo.ts │ │ │ │ └── schema.ts │ │ │ ├── models/ │ │ │ │ ├── models.ts │ │ │ │ └── repo.ts │ │ │ ├── runs/ │ │ │ │ ├── lock.ts │ │ │ │ ├── repo.ts │ │ │ │ └── runs.ts │ │ │ ├── scripts/ │ │ │ │ └── migrate-agents.ts │ │ │ ├── server.ts │ │ │ ├── shared/ │ │ │ │ └── prefix-logger.ts │ │ │ └── tui/ │ │ │ ├── api.ts │ │ │ ├── index.tsx │ │ │ └── ui.tsx │ │ ├── todo.md │ │ └── tsconfig.json │ ├── docs/ │ │ ├── .gitignore │ │ ├── docs/ │ │ │ ├── development/ │ │ │ │ ├── contribution-guide.mdx │ │ │ │ └── roadmap.mdx │ │ │ └── getting-started/ │ │ │ ├── introduction.mdx │ │ │ ├── license.mdx │ │ │ └── quickstart.mdx │ │ └── docs.json │ ├── experimental/ │ │ ├── chat_widget/ │ │ │ ├── .dockerignore │ │ │ ├── .eslintrc.json │ │ │ ├── .gitignore │ │ │ ├── Dockerfile │ │ │ ├── README.md │ │ │ ├── app/ │ │ │ │ ├── api/ │ │ │ │ │ └── bootstrap.js/ │ │ │ │ │ └── route.ts │ │ │ │ ├── app.tsx │ │ │ │ ├── globals.css │ │ │ │ ├── layout.tsx │ │ │ │ ├── markdown-content.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── providers.tsx │ │ │ ├── next.config.mjs │ │ │ ├── package.json │ │ │ ├── postcss.config.mjs │ │ │ ├── public/ │ │ │ │ └── bootstrap.template.js │ │ │ ├── tailwind.config.ts │ │ │ └── tsconfig.json │ │ ├── simulation_runner/ │ │ │ ├── Dockerfile │ │ │ ├── __init__.py │ │ │ ├── db.py │ │ │ ├── requirements.txt │ │ │ ├── scenario_types.py │ │ │ ├── service.py │ │ │ └── simulation.py │ │ └── tools_webhook/ │ │ ├── Dockerfile │ │ ├── __init__.py │ │ ├── app.py │ │ ├── function_map.py │ │ ├── requirements.txt │ │ ├── tests/ │ │ │ ├── __init__.py │ │ │ ├── test_app.py │ │ │ └── test_tool_caller.py │ │ └── tool_caller.py │ ├── python-sdk/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── pyproject.toml │ │ ├── requirements.txt │ │ └── src/ │ │ └── rowboat/ │ │ ├── __init__.py │ │ ├── client.py │ │ └── schema.py │ ├── rowboat/ │ │ ├── .dockerignore │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── app/ │ │ │ ├── actions/ │ │ │ │ ├── assistant-templates.actions.ts │ │ │ │ ├── auth.actions.ts │ │ │ │ ├── billing.actions.ts │ │ │ │ ├── composio.actions.ts │ │ │ │ ├── conversation.actions.ts │ │ │ │ ├── copilot.actions.ts │ │ │ │ ├── custom-mcp-server.actions.ts │ │ │ │ ├── data-source.actions.ts │ │ │ │ ├── job.actions.ts │ │ │ │ ├── playground-chat.actions.ts │ │ │ │ ├── project.actions.ts │ │ │ │ ├── recurring-job-rules.actions.ts │ │ │ │ ├── scheduled-job-rules.actions.ts │ │ │ │ ├── shared-workflow.actions.ts │ │ │ │ └── twilio.actions.ts │ │ │ ├── api/ │ │ │ │ ├── composio/ │ │ │ │ │ └── webhook/ │ │ │ │ │ └── route.ts │ │ │ │ ├── copilot-stream-response/ │ │ │ │ │ └── [streamId]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── generated-images/ │ │ │ │ │ └── [id]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── me/ │ │ │ │ │ └── route.ts │ │ │ │ ├── stream-response/ │ │ │ │ │ └── [streamId]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── tmp-images/ │ │ │ │ │ └── [id]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── twilio/ │ │ │ │ │ ├── inbound_call/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── turn/ │ │ │ │ │ │ └── [callSid]/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── uploads/ │ │ │ │ │ └── [fileId]/ │ │ │ │ │ └── route.ts │ │ │ │ ├── v1/ │ │ │ │ │ └── [projectId]/ │ │ │ │ │ └── chat/ │ │ │ │ │ └── route.ts │ │ │ │ └── widget/ │ │ │ │ └── v1/ │ │ │ │ ├── chats/ │ │ │ │ │ ├── [chatId]/ │ │ │ │ │ │ ├── close/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── messages/ │ │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ ├── route.ts │ │ │ │ │ │ └── turn/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ ├── session/ │ │ │ │ │ ├── guest/ │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── user/ │ │ │ │ │ └── route.ts │ │ │ │ └── utils.ts │ │ │ ├── app.tsx │ │ │ ├── billing/ │ │ │ │ ├── app.tsx │ │ │ │ ├── callback/ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── browserconfig.xml │ │ │ ├── components/ │ │ │ │ └── ui/ │ │ │ │ └── textarea-with-send.tsx │ │ │ ├── composio/ │ │ │ │ └── oauth2/ │ │ │ │ └── callback/ │ │ │ │ └── page.tsx │ │ │ ├── globals.css │ │ │ ├── hero.ts │ │ │ ├── layout.tsx │ │ │ ├── lib/ │ │ │ │ ├── assistant_templates_seed.ts │ │ │ │ ├── auth.ts │ │ │ │ ├── auth0.ts │ │ │ │ ├── billing.ts │ │ │ │ ├── client_utils.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── atmentions.ts │ │ │ │ │ ├── datasource-icon.tsx │ │ │ │ │ ├── dropdown.tsx │ │ │ │ │ ├── form-section.tsx │ │ │ │ │ ├── form-status-button-old.tsx │ │ │ │ │ ├── form-status-button.tsx │ │ │ │ │ ├── icons.tsx │ │ │ │ │ ├── input-field.tsx │ │ │ │ │ ├── label.tsx │ │ │ │ │ ├── markdown-content.tsx │ │ │ │ │ ├── mentions-editor.css │ │ │ │ │ ├── mentions_editor.tsx │ │ │ │ │ ├── menu-item.tsx │ │ │ │ │ ├── message-display.tsx │ │ │ │ │ ├── page-section.tsx │ │ │ │ │ ├── pagination.tsx │ │ │ │ │ ├── reason-badge.tsx │ │ │ │ │ ├── structured-list.tsx │ │ │ │ │ ├── structured-panel.tsx │ │ │ │ │ ├── typewriter.tsx │ │ │ │ │ └── user_button.tsx │ │ │ │ ├── default_tools.ts │ │ │ │ ├── embedding.ts │ │ │ │ ├── feature_flags.ts │ │ │ │ ├── loadenv.ts │ │ │ │ ├── mcp.ts │ │ │ │ ├── mongodb.ts │ │ │ │ ├── prebuilt-cards/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── customer-support.json │ │ │ │ │ ├── eisenhower-email-organizer.json │ │ │ │ │ ├── github-data-to-spreadsheet.json │ │ │ │ │ ├── github-issue-to-slack.json │ │ │ │ │ ├── github-pr-to-slack.json │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── interview-scheduler.json │ │ │ │ │ ├── meeting-prep-assistant.json │ │ │ │ │ ├── reddit-on-slack.json │ │ │ │ │ ├── tweet-assistant.json │ │ │ │ │ └── twitter-sentiment.json │ │ │ │ ├── project_templates.ts │ │ │ │ ├── qdrant.ts │ │ │ │ ├── redis.ts │ │ │ │ ├── types/ │ │ │ │ │ ├── api_types.ts │ │ │ │ │ ├── billing_types.ts │ │ │ │ │ ├── datasource_types.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── voice_types.ts │ │ │ │ │ └── workflow_types.ts │ │ │ │ ├── uploads_s3_client.ts │ │ │ │ └── utils.ts │ │ │ ├── loading.tsx │ │ │ ├── new-chat-link.tsx │ │ │ ├── onboarding/ │ │ │ │ ├── app.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── page.tsx │ │ │ ├── projects/ │ │ │ │ ├── [projectId]/ │ │ │ │ │ ├── config/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── project.tsx │ │ │ │ │ │ │ ├── shared-styles.ts │ │ │ │ │ │ │ └── voice.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── conversations/ │ │ │ │ │ │ ├── [conversationId]/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── conversation-view.tsx │ │ │ │ │ │ │ └── conversations-list.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── copilot/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── TriggerSetupModal.tsx │ │ │ │ │ │ │ ├── actions.tsx │ │ │ │ │ │ │ ├── messages.tsx │ │ │ │ │ │ │ └── use-trigger-actions.ts │ │ │ │ │ │ ├── example.md │ │ │ │ │ │ ├── use-copilot.tsx │ │ │ │ │ │ └── use-parsed-blocks.tsx │ │ │ │ │ ├── entities/ │ │ │ │ │ │ ├── AgentGraphVisualizer.tsx │ │ │ │ │ │ ├── agent_config.tsx │ │ │ │ │ │ ├── datasource_config.tsx │ │ │ │ │ │ ├── pipeline_config.tsx │ │ │ │ │ │ ├── prompt_config.tsx │ │ │ │ │ │ └── tool_config.tsx │ │ │ │ │ ├── jobs/ │ │ │ │ │ │ ├── [jobId]/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── job-view.tsx │ │ │ │ │ │ │ └── jobs-list.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── manage-triggers/ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── composio-trigger-deployment-view.tsx │ │ │ │ │ │ │ ├── create-recurring-job-rule-form.tsx │ │ │ │ │ │ │ ├── job-rules-tabs.tsx │ │ │ │ │ │ │ ├── recurring-job-rule-view.tsx │ │ │ │ │ │ │ ├── recurring-job-rules-list.tsx │ │ │ │ │ │ │ └── triggers-tab.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ ├── recurring/ │ │ │ │ │ │ │ ├── [ruleId]/ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ └── new/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── scheduled/ │ │ │ │ │ │ │ ├── [ruleId]/ │ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── create-scheduled-job-rule-form.tsx │ │ │ │ │ │ │ │ ├── scheduled-job-rule-view.tsx │ │ │ │ │ │ │ │ └── scheduled-job-rules-list.tsx │ │ │ │ │ │ │ └── new/ │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── triggers/ │ │ │ │ │ │ └── [deploymentId]/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── playground/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── chat.tsx │ │ │ │ │ │ │ ├── feedback-modal.tsx │ │ │ │ │ │ │ ├── messages.tsx │ │ │ │ │ │ │ └── profile-context-box.tsx │ │ │ │ │ │ └── copilot-prompts.ts │ │ │ │ │ ├── sources/ │ │ │ │ │ │ ├── [sourceId]/ │ │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ │ └── source-page.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── delete.tsx │ │ │ │ │ │ │ ├── files-source.tsx │ │ │ │ │ │ │ ├── scrape-source.tsx │ │ │ │ │ │ │ ├── section.tsx │ │ │ │ │ │ │ ├── self-updating-source-status.tsx │ │ │ │ │ │ │ ├── shared.tsx │ │ │ │ │ │ │ ├── source-status.tsx │ │ │ │ │ │ │ ├── sources-list.tsx │ │ │ │ │ │ │ ├── text-source.tsx │ │ │ │ │ │ │ ├── toggle-source.tsx │ │ │ │ │ │ │ └── web-recrawl.tsx │ │ │ │ │ │ ├── new/ │ │ │ │ │ │ │ ├── form.tsx │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── tools/ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── AddWebhookTool.tsx │ │ │ │ │ │ │ ├── ComposioToolsPanel.tsx │ │ │ │ │ │ │ ├── CustomMcpServer.tsx │ │ │ │ │ │ │ ├── MCPServersCommon.tsx │ │ │ │ │ │ │ ├── McpToolsPanel.tsx │ │ │ │ │ │ │ ├── SelectComposioToolkit.tsx │ │ │ │ │ │ │ ├── ServerCard.tsx │ │ │ │ │ │ │ ├── ToolkitAuthModal.tsx │ │ │ │ │ │ │ ├── ToolkitCard.tsx │ │ │ │ │ │ │ ├── ToolsConfig.tsx │ │ │ │ │ │ │ └── WebhookConfig.tsx │ │ │ │ │ │ └── oauth/ │ │ │ │ │ │ └── callback/ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── workflow/ │ │ │ │ │ ├── app.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ComposioTriggerTypesPanel.tsx │ │ │ │ │ │ ├── DataSourcesModal.tsx │ │ │ │ │ │ ├── ToolsModal.tsx │ │ │ │ │ │ ├── TopBar.tsx │ │ │ │ │ │ └── TriggerConfigForm.tsx │ │ │ │ │ ├── config_list.tsx │ │ │ │ │ ├── entity_list.tsx │ │ │ │ │ ├── error.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── pane.tsx │ │ │ │ │ ├── preview-modal.tsx │ │ │ │ │ ├── trigger-transform.ts │ │ │ │ │ └── workflow_editor.tsx │ │ │ │ ├── app.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── build-assistant-section.tsx │ │ │ │ │ ├── create-project.tsx │ │ │ │ │ ├── custom-prompt-card.tsx │ │ │ │ │ ├── project-list.tsx │ │ │ │ │ ├── search-input.tsx │ │ │ │ │ ├── search-projects.tsx │ │ │ │ │ ├── submit-button.tsx │ │ │ │ │ └── templates-section.tsx │ │ │ │ ├── layout/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── app-layout.tsx │ │ │ │ │ │ ├── menu-item.tsx │ │ │ │ │ │ └── sidebar.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── menu.tsx │ │ │ │ │ └── nav.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── lib/ │ │ │ │ │ └── project-creation-utils.ts │ │ │ │ └── page.tsx │ │ │ ├── providers/ │ │ │ │ ├── help-modal-provider.tsx │ │ │ │ └── theme-provider.tsx │ │ │ ├── providers.tsx │ │ │ ├── scripts/ │ │ │ │ ├── delete_qdrant.ts │ │ │ │ ├── job-rules.worker.ts │ │ │ │ ├── jobs-worker.ts │ │ │ │ ├── mongodb-drop-indexes.ts │ │ │ │ ├── mongodb-ensure-indexes.ts │ │ │ │ ├── rag-worker.ts │ │ │ │ └── setup_qdrant.ts │ │ │ ├── site.webmanifest │ │ │ └── styles/ │ │ │ ├── design-tokens.ts │ │ │ ├── pane-effects.ts │ │ │ └── quill-mentions.css │ │ ├── components/ │ │ │ ├── common/ │ │ │ │ ├── AssistantCard.tsx │ │ │ │ ├── AssistantSection.tsx │ │ │ │ ├── UnifiedTemplatesSection.tsx │ │ │ │ ├── billing-upgrade-modal.tsx │ │ │ │ ├── compose-box-copilot.tsx │ │ │ │ ├── compose-box-playground.tsx │ │ │ │ ├── compose-box.tsx │ │ │ │ ├── copy-as-json-button.tsx │ │ │ │ ├── copy-button.tsx │ │ │ │ ├── help-modal.tsx │ │ │ │ ├── panel-common.tsx │ │ │ │ ├── product-tour.tsx │ │ │ │ ├── project-wide-change-confirmation-modal.tsx │ │ │ │ ├── section-card.tsx │ │ │ │ └── tool-param-card.tsx │ │ │ └── ui/ │ │ │ ├── button.tsx │ │ │ ├── dropdown.tsx │ │ │ ├── horizontal-divider.tsx │ │ │ ├── input.tsx │ │ │ ├── modal.tsx │ │ │ ├── page-header.tsx │ │ │ ├── page-heading.tsx │ │ │ ├── picture-img.tsx │ │ │ ├── progress-bar.tsx │ │ │ ├── resizable.tsx │ │ │ ├── search-bar.tsx │ │ │ ├── section-heading.tsx │ │ │ ├── slide-panel.tsx │ │ │ ├── switch.tsx │ │ │ ├── tabs.tsx │ │ │ └── textarea.tsx │ │ ├── components.json │ │ ├── di/ │ │ │ └── container.ts │ │ ├── hooks/ │ │ │ └── use-click-away.ts │ │ ├── instrumentation-client.ts │ │ ├── lib/ │ │ │ ├── utils/ │ │ │ │ └── date.ts │ │ │ └── utils.ts │ │ ├── middleware.ts │ │ ├── next.config.mjs │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── scripts.Dockerfile │ │ ├── src/ │ │ │ ├── application/ │ │ │ │ ├── lib/ │ │ │ │ │ ├── agents-runtime/ │ │ │ │ │ │ ├── agent-handoffs.ts │ │ │ │ │ │ ├── agent-tools.ts │ │ │ │ │ │ ├── agent_instructions.ts │ │ │ │ │ │ ├── agents.ts │ │ │ │ │ │ └── pipeline-state-manager.ts │ │ │ │ │ ├── composio/ │ │ │ │ │ │ ├── composio.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── copilot/ │ │ │ │ │ │ ├── copilot.ts │ │ │ │ │ │ ├── copilot_edit_agent.ts │ │ │ │ │ │ ├── copilot_multi_agent.ts │ │ │ │ │ │ ├── copilot_multi_agent_build.ts │ │ │ │ │ │ ├── current_workflow.ts │ │ │ │ │ │ └── example_multi_agent_1.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── is-valid-cron-expression.ts │ │ │ │ │ └── time-to-next-minute.ts │ │ │ │ ├── policies/ │ │ │ │ │ ├── project-action-authorization.policy.ts │ │ │ │ │ └── usage-quota.policy.interface.ts │ │ │ │ ├── repositories/ │ │ │ │ │ ├── api-keys.repository.interface.ts │ │ │ │ │ ├── composio-trigger-deployments.repository.interface.ts │ │ │ │ │ ├── conversations.repository.interface.ts │ │ │ │ │ ├── data-source-docs.repository.interface.ts │ │ │ │ │ ├── data-sources.repository.interface.ts │ │ │ │ │ ├── jobs.repository.interface.ts │ │ │ │ │ ├── project-members.repository.interface.ts │ │ │ │ │ ├── projects.repository.interface.ts │ │ │ │ │ ├── recurring-job-rules.repository.interface.ts │ │ │ │ │ ├── scheduled-job-rules.repository.interface.ts │ │ │ │ │ └── users.repository.interface.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── cache.service.interface.ts │ │ │ │ │ ├── pub-sub.service.interface.ts │ │ │ │ │ ├── temp-binary-cache.ts │ │ │ │ │ └── uploads-storage.service.interface.ts │ │ │ │ ├── use-cases/ │ │ │ │ │ ├── api-keys/ │ │ │ │ │ │ ├── create-api-key.use-case.ts │ │ │ │ │ │ ├── delete-api-key.use-case.ts │ │ │ │ │ │ └── list-api-keys.use-case.ts │ │ │ │ │ ├── composio/ │ │ │ │ │ │ └── webhook/ │ │ │ │ │ │ └── handle-composio-webhook-request.use-case.ts │ │ │ │ │ ├── composio-trigger-deployments/ │ │ │ │ │ │ ├── create-composio-trigger-deployment.use-case.ts │ │ │ │ │ │ ├── delete-composio-trigger-deployment.use-case.ts │ │ │ │ │ │ ├── fetch-composio-trigger-deployment.use-case.ts │ │ │ │ │ │ ├── list-composio-trigger-deployments.use-case.ts │ │ │ │ │ │ └── list-composio-trigger-types.use-case.ts │ │ │ │ │ ├── conversations/ │ │ │ │ │ │ ├── create-cached-turn.use-case.ts │ │ │ │ │ │ ├── create-conversation.use-case.ts │ │ │ │ │ │ ├── fetch-cached-turn.use-case.ts │ │ │ │ │ │ ├── fetch-conversation.use-case.ts │ │ │ │ │ │ ├── list-conversations.use-case.ts │ │ │ │ │ │ └── run-conversation-turn.use-case.ts │ │ │ │ │ ├── copilot/ │ │ │ │ │ │ ├── create-copilot-cached-turn.use-case.ts │ │ │ │ │ │ └── run-copilot-cached-turn.use-case.ts │ │ │ │ │ ├── data-sources/ │ │ │ │ │ │ ├── add-docs-to-data-source.use-case.ts │ │ │ │ │ │ ├── create-data-source.use-case.ts │ │ │ │ │ │ ├── delete-data-source.use-case.ts │ │ │ │ │ │ ├── delete-doc-from-data-source.use-case.ts │ │ │ │ │ │ ├── fetch-data-source.use-case.ts │ │ │ │ │ │ ├── get-download-url-for-file.use-case.ts │ │ │ │ │ │ ├── get-upload-urls-for-files.use-case.ts │ │ │ │ │ │ ├── list-data-sources.use-case.ts │ │ │ │ │ │ ├── list-docs-in-data-source.use-case.ts │ │ │ │ │ │ ├── recrawl-web-data-source.use-case.ts │ │ │ │ │ │ ├── toggle-data-source.use-case.ts │ │ │ │ │ │ └── update-data-source.use-case.ts │ │ │ │ │ ├── jobs/ │ │ │ │ │ │ ├── fetch-job.use-case.ts │ │ │ │ │ │ └── list-jobs.use-case.ts │ │ │ │ │ ├── projects/ │ │ │ │ │ │ ├── add-custom-mcp-server.use-case.ts │ │ │ │ │ │ ├── create-composio-managed-connected-account.use-case.ts │ │ │ │ │ │ ├── create-custom-connected-account.use-case.ts │ │ │ │ │ │ ├── create-project.use-case.ts │ │ │ │ │ │ ├── delete-composio-connected-account.use-case.ts │ │ │ │ │ │ ├── delete-project.use-case.ts │ │ │ │ │ │ ├── fetch-project.use-case.ts │ │ │ │ │ │ ├── get-composio-toolkit.use-case.ts │ │ │ │ │ │ ├── list-composio-toolkits.use-case.ts │ │ │ │ │ │ ├── list-composio-tools.use-case.ts │ │ │ │ │ │ ├── list-projects.use-case.ts │ │ │ │ │ │ ├── remove-custom-mcp-server.use-case.ts │ │ │ │ │ │ ├── revert-to-live-workflow.use-case.ts │ │ │ │ │ │ ├── rotate-secret.use-case.ts │ │ │ │ │ │ ├── sync-connected-account.use-case.ts │ │ │ │ │ │ ├── update-draft-workflow.use-case.ts │ │ │ │ │ │ ├── update-live-workflow.use-case.ts │ │ │ │ │ │ ├── update-project-name.use-case.ts │ │ │ │ │ │ └── update-webhook-url.use-case.ts │ │ │ │ │ ├── recurring-job-rules/ │ │ │ │ │ │ ├── create-recurring-job-rule.use-case.ts │ │ │ │ │ │ ├── delete-recurring-job-rule.use-case.ts │ │ │ │ │ │ ├── fetch-recurring-job-rule.use-case.ts │ │ │ │ │ │ ├── list-recurring-job-rules.use-case.ts │ │ │ │ │ │ ├── toggle-recurring-job-rule.use-case.ts │ │ │ │ │ │ └── update-recurring-job-rule.use-case.ts │ │ │ │ │ └── scheduled-job-rules/ │ │ │ │ │ ├── create-scheduled-job-rule.use-case.ts │ │ │ │ │ ├── delete-scheduled-job-rule.use-case.ts │ │ │ │ │ ├── fetch-scheduled-job-rule.use-case.ts │ │ │ │ │ ├── list-scheduled-job-rules.use-case.ts │ │ │ │ │ └── update-scheduled-job-rule.use-case.ts │ │ │ │ └── workers/ │ │ │ │ ├── job-rules.worker.ts │ │ │ │ └── jobs.worker.ts │ │ │ ├── entities/ │ │ │ │ ├── common/ │ │ │ │ │ └── paginated-list.ts │ │ │ │ ├── errors/ │ │ │ │ │ ├── common.ts │ │ │ │ │ └── job-errors.ts │ │ │ │ └── models/ │ │ │ │ ├── api-key.ts │ │ │ │ ├── assistant-template.ts │ │ │ │ ├── composio-trigger-deployment.ts │ │ │ │ ├── composio-trigger-type.ts │ │ │ │ ├── conversation.ts │ │ │ │ ├── copilot.ts │ │ │ │ ├── data-source-doc.ts │ │ │ │ ├── data-source.ts │ │ │ │ ├── job.ts │ │ │ │ ├── project-member.ts │ │ │ │ ├── project.ts │ │ │ │ ├── recurring-job-rule.ts │ │ │ │ ├── scheduled-job-rule.ts │ │ │ │ ├── turn.ts │ │ │ │ └── user.ts │ │ │ ├── infrastructure/ │ │ │ │ ├── mongodb/ │ │ │ │ │ ├── drop-indexes.ts │ │ │ │ │ └── ensure-indexes.ts │ │ │ │ ├── policies/ │ │ │ │ │ └── redis.usage-quota.policy.ts │ │ │ │ ├── repositories/ │ │ │ │ │ ├── mongodb.api-keys.indexes.ts │ │ │ │ │ ├── mongodb.api-keys.repository.ts │ │ │ │ │ ├── mongodb.assistant-templates.repository.ts │ │ │ │ │ ├── mongodb.community-assistants.indexes.ts │ │ │ │ │ ├── mongodb.composio-trigger-deployments.indexes.ts │ │ │ │ │ ├── mongodb.composio-trigger-deployments.repository.ts │ │ │ │ │ ├── mongodb.conversations.indexes.ts │ │ │ │ │ ├── mongodb.conversations.repository.ts │ │ │ │ │ ├── mongodb.data-source-docs.indexes.ts │ │ │ │ │ ├── mongodb.data-source-docs.repository.ts │ │ │ │ │ ├── mongodb.data-sources.indexes.ts │ │ │ │ │ ├── mongodb.data-sources.repository.ts │ │ │ │ │ ├── mongodb.jobs.indexes.ts │ │ │ │ │ ├── mongodb.jobs.repository.ts │ │ │ │ │ ├── mongodb.project-members.indexes.ts │ │ │ │ │ ├── mongodb.project-members.repository.ts │ │ │ │ │ ├── mongodb.projects.indexes.ts │ │ │ │ │ ├── mongodb.projects.repository.ts │ │ │ │ │ ├── mongodb.recurring-job-rules.indexes.ts │ │ │ │ │ ├── mongodb.recurring-job-rules.repository.ts │ │ │ │ │ ├── mongodb.scheduled-job-rules.indexes.ts │ │ │ │ │ ├── mongodb.scheduled-job-rules.repository.ts │ │ │ │ │ ├── mongodb.shared-workflows.indexes.ts │ │ │ │ │ ├── mongodb.users.indexes.ts │ │ │ │ │ └── mongodb.users.repository.ts │ │ │ │ └── services/ │ │ │ │ ├── local.uploads-storage.service.ts │ │ │ │ ├── redis.cache.service.ts │ │ │ │ ├── redis.pub-sub.service.ts │ │ │ │ └── s3.uploads-storage.service.ts │ │ │ └── interface-adapters/ │ │ │ └── controllers/ │ │ │ ├── api-keys/ │ │ │ │ ├── create-api-key.controller.ts │ │ │ │ ├── delete-api-key.controller.ts │ │ │ │ └── list-api-keys.controller.ts │ │ │ ├── composio/ │ │ │ │ └── webhook/ │ │ │ │ └── handle-composio-webhook-request.controller.ts │ │ │ ├── composio-trigger-deployments/ │ │ │ │ ├── create-composio-trigger-deployment.controller.ts │ │ │ │ ├── delete-composio-trigger-deployment.controller.ts │ │ │ │ ├── fetch-composio-trigger-deployment.controller.ts │ │ │ │ ├── list-composio-trigger-deployments.controller.ts │ │ │ │ └── list-composio-trigger-types.controller.ts │ │ │ ├── conversations/ │ │ │ │ ├── create-cached-turn.controller.ts │ │ │ │ ├── create-playground-conversation.controller.ts │ │ │ │ ├── fetch-conversation.controller.ts │ │ │ │ ├── list-conversations.controller.ts │ │ │ │ ├── run-cached-turn.controller.ts │ │ │ │ └── run-turn.controller.ts │ │ │ ├── copilot/ │ │ │ │ ├── create-copilot-cached-turn.controller.ts │ │ │ │ └── run-copilot-cached-turn.controller.ts │ │ │ ├── data-sources/ │ │ │ │ ├── add-docs-to-data-source.controller.ts │ │ │ │ ├── create-data-source.controller.ts │ │ │ │ ├── delete-data-source.controller.ts │ │ │ │ ├── delete-doc-from-data-source.controller.ts │ │ │ │ ├── fetch-data-source.controller.ts │ │ │ │ ├── get-download-url-for-file.controller.ts │ │ │ │ ├── get-upload-urls-for-files.controller.ts │ │ │ │ ├── list-data-sources.controller.ts │ │ │ │ ├── list-docs-in-data-source.controller.ts │ │ │ │ ├── recrawl-web-data-source.controller.ts │ │ │ │ ├── toggle-data-source.controller.ts │ │ │ │ └── update-data-source.controller.ts │ │ │ ├── jobs/ │ │ │ │ ├── fetch-job.controller.ts │ │ │ │ └── list-jobs.controller.ts │ │ │ ├── projects/ │ │ │ │ ├── add-custom-mcp-server.controller.ts │ │ │ │ ├── create-composio-managed-connected-account.controller.ts │ │ │ │ ├── create-custom-connected-account.controller.ts │ │ │ │ ├── create-project.controller.ts │ │ │ │ ├── delete-composio-connected-account.controller.ts │ │ │ │ ├── delete-project.controller.ts │ │ │ │ ├── fetch-project.controller.ts │ │ │ │ ├── get-composio-toolkit.controller.ts │ │ │ │ ├── list-composio-toolkits.controller.ts │ │ │ │ ├── list-composio-tools.controller.ts │ │ │ │ ├── list-projects.controller.ts │ │ │ │ ├── remove-custom-mcp-server.controller.ts │ │ │ │ ├── revert-to-live-workflow.controller.ts │ │ │ │ ├── rotate-secret.controller.ts │ │ │ │ ├── sync-connected-account.controller.ts │ │ │ │ ├── update-draft-workflow.controller.ts │ │ │ │ ├── update-live-workflow.controller.ts │ │ │ │ ├── update-project-name.controller.ts │ │ │ │ └── update-webhook-url.controller.ts │ │ │ ├── recurring-job-rules/ │ │ │ │ ├── create-recurring-job-rule.controller.ts │ │ │ │ ├── delete-recurring-job-rule.controller.ts │ │ │ │ ├── fetch-recurring-job-rule.controller.ts │ │ │ │ ├── list-recurring-job-rules.controller.ts │ │ │ │ ├── toggle-recurring-job-rule.controller.ts │ │ │ │ └── update-recurring-job-rule.controller.ts │ │ │ └── scheduled-job-rules/ │ │ │ ├── create-scheduled-job-rule.controller.ts │ │ │ ├── delete-scheduled-job-rule.controller.ts │ │ │ ├── fetch-scheduled-job-rule.controller.ts │ │ │ ├── list-scheduled-job-rules.controller.ts │ │ │ └── update-scheduled-job-rule.controller.ts │ │ └── tsconfig.json │ ├── rowboatx/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app/ │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── components/ │ │ │ ├── ai-elements/ │ │ │ │ ├── artifact.tsx │ │ │ │ ├── canvas.tsx │ │ │ │ ├── chain-of-thought.tsx │ │ │ │ ├── checkpoint.tsx │ │ │ │ ├── code-block.tsx │ │ │ │ ├── confirmation.tsx │ │ │ │ ├── connection.tsx │ │ │ │ ├── context.tsx │ │ │ │ ├── controls.tsx │ │ │ │ ├── conversation.tsx │ │ │ │ ├── edge.tsx │ │ │ │ ├── image.tsx │ │ │ │ ├── inline-citation.tsx │ │ │ │ ├── loader.tsx │ │ │ │ ├── message.tsx │ │ │ │ ├── model-selector.tsx │ │ │ │ ├── node.tsx │ │ │ │ ├── open-in-chat.tsx │ │ │ │ ├── panel.tsx │ │ │ │ ├── plan.tsx │ │ │ │ ├── prompt-input.tsx │ │ │ │ ├── queue.tsx │ │ │ │ ├── reasoning.tsx │ │ │ │ ├── shimmer.tsx │ │ │ │ ├── sources.tsx │ │ │ │ ├── suggestion.tsx │ │ │ │ ├── task.tsx │ │ │ │ ├── tool.tsx │ │ │ │ ├── toolbar.tsx │ │ │ │ └── web-preview.tsx │ │ │ ├── app-sidebar.tsx │ │ │ ├── json-editor.css │ │ │ ├── json-editor.tsx │ │ │ ├── markdown-viewer.css │ │ │ ├── markdown-viewer.tsx │ │ │ ├── nav-main.tsx │ │ │ ├── nav-projects.tsx │ │ │ ├── nav-user.tsx │ │ │ ├── team-switcher.tsx │ │ │ ├── tiptap-markdown-editor.css │ │ │ ├── tiptap-markdown-editor.tsx │ │ │ └── ui/ │ │ │ ├── alert.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── breadcrumb.tsx │ │ │ ├── button-group.tsx │ │ │ ├── button.tsx │ │ │ ├── card.tsx │ │ │ ├── carousel.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── command.tsx │ │ │ ├── dialog.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── hover-card.tsx │ │ │ ├── input-group.tsx │ │ │ ├── input.tsx │ │ │ ├── progress.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── sidebar.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── textarea.tsx │ │ │ └── tooltip.tsx │ │ ├── components.json │ │ ├── eslint.config.mjs │ │ ├── global.d.ts │ │ ├── hooks/ │ │ │ └── use-mobile.ts │ │ ├── lib/ │ │ │ └── utils.ts │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── postcss.config.mjs │ │ ├── tsconfig.json │ │ └── types/ │ │ └── turndown.d.ts │ └── x/ │ ├── .gitignore │ ├── apps/ │ │ ├── main/ │ │ │ ├── .gitignore │ │ │ ├── bundle.mjs │ │ │ ├── forge.config.cjs │ │ │ ├── icons/ │ │ │ │ └── icon.icns │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── auth-server.ts │ │ │ │ ├── composio-handler.ts │ │ │ │ ├── ipc.ts │ │ │ │ ├── main.ts │ │ │ │ ├── oauth-handler.ts │ │ │ │ └── test-agent.ts │ │ │ └── tsconfig.json │ │ ├── preload/ │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ └── preload.ts │ │ │ └── tsconfig.json │ │ └── renderer/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── components.json │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── components/ │ │ │ │ ├── ai-elements/ │ │ │ │ │ ├── ask-human-request.tsx │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── conversation.tsx │ │ │ │ │ ├── file-path-card.tsx │ │ │ │ │ ├── markdown-code-override.tsx │ │ │ │ │ ├── message.tsx │ │ │ │ │ ├── permission-request.tsx │ │ │ │ │ ├── prompt-input.tsx │ │ │ │ │ ├── reasoning.tsx │ │ │ │ │ ├── shimmer.tsx │ │ │ │ │ ├── suggestions.tsx │ │ │ │ │ ├── tool.tsx │ │ │ │ │ └── web-search-result.tsx │ │ │ │ ├── background-task-detail.tsx │ │ │ │ ├── chat-button.tsx │ │ │ │ ├── chat-input-with-mentions.tsx │ │ │ │ ├── chat-message-attachments.tsx │ │ │ │ ├── chat-sidebar.tsx │ │ │ │ ├── composio-api-key-modal.tsx │ │ │ │ ├── connectors-popover.tsx │ │ │ │ ├── editor-toolbar.tsx │ │ │ │ ├── google-client-id-modal.tsx │ │ │ │ ├── graph-view.tsx │ │ │ │ ├── help-popover.tsx │ │ │ │ ├── markdown-editor.tsx │ │ │ │ ├── mention-popover.tsx │ │ │ │ ├── onboarding-modal.tsx │ │ │ │ ├── search-dialog.tsx │ │ │ │ ├── settings-dialog.tsx │ │ │ │ ├── sidebar-content.tsx │ │ │ │ ├── tab-bar.tsx │ │ │ │ ├── ui/ │ │ │ │ │ ├── alert-dialog.tsx │ │ │ │ │ ├── badge.tsx │ │ │ │ │ ├── button-group.tsx │ │ │ │ │ ├── button.tsx │ │ │ │ │ ├── collapsible.tsx │ │ │ │ │ ├── command.tsx │ │ │ │ │ ├── context-menu.tsx │ │ │ │ │ ├── dialog.tsx │ │ │ │ │ ├── dropdown-menu.tsx │ │ │ │ │ ├── hover-card.tsx │ │ │ │ │ ├── input-group.tsx │ │ │ │ │ ├── input.tsx │ │ │ │ │ ├── popover.tsx │ │ │ │ │ ├── progress.tsx │ │ │ │ │ ├── select.tsx │ │ │ │ │ ├── separator.tsx │ │ │ │ │ ├── sheet.tsx │ │ │ │ │ ├── sidebar.tsx │ │ │ │ │ ├── skeleton.tsx │ │ │ │ │ ├── sonner.tsx │ │ │ │ │ ├── switch.tsx │ │ │ │ │ ├── textarea.tsx │ │ │ │ │ └── tooltip.tsx │ │ │ │ └── version-history-panel.tsx │ │ │ ├── contexts/ │ │ │ │ ├── file-card-context.tsx │ │ │ │ ├── sidebar-context.tsx │ │ │ │ └── theme-context.tsx │ │ │ ├── extensions/ │ │ │ │ ├── image-upload.tsx │ │ │ │ └── wiki-link.ts │ │ │ ├── global.d.ts │ │ │ ├── hooks/ │ │ │ │ ├── use-debounce.ts │ │ │ │ ├── use-mention-detection.ts │ │ │ │ ├── use-mobile.ts │ │ │ │ └── useOAuth.ts │ │ │ ├── index.css │ │ │ ├── lib/ │ │ │ │ ├── attachment-presentation.ts │ │ │ │ ├── chat-conversation.ts │ │ │ │ ├── file-utils.ts │ │ │ │ ├── google-client-id-store.ts │ │ │ │ ├── mention-files.ts │ │ │ │ ├── mention-highlights.ts │ │ │ │ ├── textarea-caret.ts │ │ │ │ ├── toast.ts │ │ │ │ ├── utils.ts │ │ │ │ └── wiki-links.ts │ │ │ ├── main.tsx │ │ │ └── styles/ │ │ │ └── editor.css │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── eslint.config.mts │ ├── package.json │ ├── packages/ │ │ ├── core/ │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── agent-schedule/ │ │ │ │ │ ├── repo.ts │ │ │ │ │ ├── runner.ts │ │ │ │ │ └── state-repo.ts │ │ │ │ ├── agents/ │ │ │ │ │ ├── repo.ts │ │ │ │ │ └── runtime.ts │ │ │ │ ├── application/ │ │ │ │ │ ├── assistant/ │ │ │ │ │ │ ├── agent.ts │ │ │ │ │ │ ├── instructions.ts │ │ │ │ │ │ ├── runtime-context.ts │ │ │ │ │ │ └── skills/ │ │ │ │ │ │ ├── background-agents/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── builtin-tools/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── create-presentations/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── deletion-guardrails/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── doc-collab/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── draft-emails/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── mcp-integration/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── meeting-prep/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── organize-files/ │ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ │ ├── slack/ │ │ │ │ │ │ │ ├── skill.ts │ │ │ │ │ │ │ └── tool-catalog.ts │ │ │ │ │ │ └── web-search/ │ │ │ │ │ │ └── skill.ts │ │ │ │ │ └── lib/ │ │ │ │ │ ├── builtin-tools.ts │ │ │ │ │ ├── bus.ts │ │ │ │ │ ├── command-executor.ts │ │ │ │ │ ├── exec-tool.ts │ │ │ │ │ ├── id-gen.ts │ │ │ │ │ └── message-queue.ts │ │ │ │ ├── auth/ │ │ │ │ │ ├── client-repo.ts │ │ │ │ │ ├── oauth-client.ts │ │ │ │ │ ├── provider-client-id.ts │ │ │ │ │ ├── providers.ts │ │ │ │ │ ├── repo.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── composio/ │ │ │ │ │ ├── client.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── repo.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── config/ │ │ │ │ │ ├── config.ts │ │ │ │ │ ├── initConfigs.ts │ │ │ │ │ ├── note_creation_config.ts │ │ │ │ │ ├── security.ts │ │ │ │ │ └── strictness_analyzer.ts │ │ │ │ ├── di/ │ │ │ │ │ └── container.ts │ │ │ │ ├── index.ts │ │ │ │ ├── knowledge/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── build_graph.ts │ │ │ │ │ ├── fireflies-client-factory.ts │ │ │ │ │ ├── google-client-factory.ts │ │ │ │ │ ├── granola/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── repo.ts │ │ │ │ │ │ ├── sync.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── graph_state.ts │ │ │ │ │ ├── knowledge_index.ts │ │ │ │ │ ├── limit_event_items.ts │ │ │ │ │ ├── note_creation_high.ts │ │ │ │ │ ├── note_creation_low.ts │ │ │ │ │ ├── note_creation_medium.ts │ │ │ │ │ ├── sync_calendar.ts │ │ │ │ │ ├── sync_fireflies.ts │ │ │ │ │ ├── sync_gmail.ts │ │ │ │ │ ├── version_history.ts │ │ │ │ │ └── welcome.md │ │ │ │ ├── mcp/ │ │ │ │ │ ├── mcp.ts │ │ │ │ │ └── repo.ts │ │ │ │ ├── models/ │ │ │ │ │ ├── models-dev.ts │ │ │ │ │ ├── models.ts │ │ │ │ │ └── repo.ts │ │ │ │ ├── pre_built/ │ │ │ │ │ ├── config.ts │ │ │ │ │ ├── email-draft.md │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── meeting-prep.md │ │ │ │ │ ├── runner.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── runs/ │ │ │ │ │ ├── abort-registry.ts │ │ │ │ │ ├── bus.ts │ │ │ │ │ ├── lock.ts │ │ │ │ │ ├── repo.ts │ │ │ │ │ └── runs.ts │ │ │ │ ├── search/ │ │ │ │ │ └── search.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── service_bus.ts │ │ │ │ │ └── service_logger.ts │ │ │ │ └── workspace/ │ │ │ │ ├── watcher.ts │ │ │ │ ├── wiki-link-rewrite.ts │ │ │ │ └── workspace.ts │ │ │ └── tsconfig.json │ │ └── shared/ │ │ ├── .gitignore │ │ ├── package.json │ │ ├── src/ │ │ │ ├── agent-schedule-state.ts │ │ │ ├── agent-schedule.ts │ │ │ ├── agent.ts │ │ │ ├── example.ts │ │ │ ├── index.ts │ │ │ ├── ipc.ts │ │ │ ├── llm-step-events.ts │ │ │ ├── mcp.ts │ │ │ ├── message.ts │ │ │ ├── models.ts │ │ │ ├── prefix-logger.ts │ │ │ ├── runs.ts │ │ │ ├── service-events.ts │ │ │ └── workspace.ts │ │ └── tsconfig.json │ ├── pnpm-workspace.yaml │ └── tsconfig.base.json ├── build-electron.sh ├── docker-compose.yml ├── google-setup.md └── start.sh
Showing preview only (340K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3392 symbols across 676 files)
FILE: apps/cli/src/agents/repo.ts
type IAgentsRepo (line 11) | interface IAgentsRepo {
class FSAgentsRepo (line 19) | class FSAgentsRepo implements IAgentsRepo {
method list (line 22) | async list(): Promise<z.infer<typeof Agent>[]> {
method parseAgentMd (line 39) | private async parseAgentMd(filePath: string): Promise<z.infer<typeof A...
method fetch (line 75) | async fetch(id: string): Promise<z.infer<typeof Agent>> {
method create (line 79) | async create(agent: z.infer<typeof Agent>): Promise<void> {
method update (line 85) | async update(id: string, agent: z.infer<typeof UpdateAgentSchema>): Pr...
method delete (line 91) | async delete(id: string): Promise<void> {
FILE: apps/cli/src/agents/runtime.ts
type IAgentRuntime (line 26) | interface IAgentRuntime {
class AgentRuntime (line 30) | class AgentRuntime implements IAgentRuntime {
method constructor (line 38) | constructor({
method trigger (line 61) | async trigger(runId: string): Promise<void> {
function mapAgentTool (line 112) | async function mapAgentTool(t: z.infer<typeof ToolAttachment>): Promise<...
class RunLogger (line 152) | class RunLogger {
method ensureRunsDir (line 156) | ensureRunsDir() {
method constructor (line 163) | constructor(runId: string) {
method log (line 172) | log(event: z.infer<typeof RunEvent>) {
method close (line 178) | close() {
class StreamStepMessageBuilder (line 183) | class StreamStepMessageBuilder {
method flushBuffers (line 189) | flushBuffers() {
method ingest (line 201) | ingest(event: z.infer<typeof LlmStepStreamEvent>) {
method get (line 230) | get(): z.infer<typeof AssistantMessage> {
function normaliseAskHumanToolCall (line 240) | function normaliseAskHumanToolCall(message: z.infer<typeof AssistantMess...
function loadAgent (line 264) | async function loadAgent(id: string): Promise<z.infer<typeof Agent>> {
function convertFromMessages (line 272) | function convertFromMessages(messages: z.infer<typeof Message>[]): Model...
function buildTools (line 344) | async function buildTools(agent: z.infer<typeof Agent>): Promise<ToolSet> {
class AgentState (line 357) | class AgentState {
method getPendingPermissions (line 371) | getPendingPermissions(): z.infer<typeof ToolPermissionRequestEvent>[] {
method getPendingAskHumans (line 390) | getPendingAskHumans(): z.infer<typeof AskHumanRequestEvent>[] {
method finalResponse (line 409) | finalResponse(): string {
method ingest (line 424) | ingest(event: z.infer<typeof RunEvent>) {
FILE: apps/cli/src/app.ts
function renderGreeting (line 20) | function renderGreeting() {
function app (line 38) | async function app(opts: {
function getToolCallPermission (line 154) | async function getToolCallPermission(
function getAskHumanResponse (line 173) | async function getAskHumanResponse(
function getUserInput (line 186) | async function getUserInput(
function modelConfig (line 197) | async function modelConfig() {
function renderCurrentModel (line 379) | function renderCurrentModel(provider: string, flavor: string, model: str...
function listAvailableExamples (line 386) | async function listAvailableExamples(): Promise<string[]> {
function writeAgents (line 390) | async function writeAgents(agents: z.infer<typeof Agent>[] | undefined) {
function mergeMcpServers (line 403) | async function mergeMcpServers(servers: Record<string, z.infer<typeof Mc...
function importExample (line 444) | async function importExample(exampleName?: string, filePath?: string) {
function listExamples (line 516) | async function listExamples() {
function exportWorkflow (line 520) | async function exportWorkflow(entryAgentName: string) {
FILE: apps/cli/src/application/assistant/runtime-context.ts
type RuntimeShellDialect (line 1) | type RuntimeShellDialect = 'windows-cmd' | 'posix-sh';
type RuntimeOsName (line 2) | type RuntimeOsName = 'Windows' | 'macOS' | 'Linux' | 'Unknown';
type RuntimeContext (line 4) | interface RuntimeContext {
function getExecutionShell (line 11) | function getExecutionShell(platform: NodeJS.Platform = process.platform)...
function getRuntimeContext (line 15) | function getRuntimeContext(platform: NodeJS.Platform = process.platform)...
function getRuntimeContextPrompt (line 51) | function getRuntimeContextPrompt(runtime: RuntimeContext): string {
FILE: apps/cli/src/application/assistant/skills/index.ts
constant CURRENT_FILE (line 9) | const CURRENT_FILE = fileURLToPath(import.meta.url);
constant CURRENT_DIR (line 10) | const CURRENT_DIR = path.dirname(CURRENT_FILE);
constant CATALOG_PREFIX (line 11) | const CATALOG_PREFIX = "src/application/assistant/skills";
type SkillDefinition (line 13) | type SkillDefinition = {
type ResolvedSkill (line 21) | type ResolvedSkill = {
function resolveSkill (line 146) | function resolveSkill(identifier: string): ResolvedSkill | null {
FILE: apps/cli/src/application/lib/builtin-tools.ts
function explore (line 53) | async function explore(dir: string, depth: number = 0): Promise<any> {
FILE: apps/cli/src/application/lib/bus.ts
type IBus (line 4) | interface IBus {
class InMemoryBus (line 12) | class InMemoryBus implements IBus {
method publish (line 15) | async publish(event: z.infer<typeof RunEvent>): Promise<void> {
method subscribe (line 26) | async subscribe(runId: string, handler: (event: z.infer<typeof RunEven...
FILE: apps/cli/src/application/lib/command-executor.ts
constant COMMAND_SPLIT_REGEX (line 7) | const COMMAND_SPLIT_REGEX = /(?:\|\||&&|;|\||\n)/;
constant ENV_ASSIGNMENT_REGEX (line 8) | const ENV_ASSIGNMENT_REGEX = /^[A-Za-z_][A-Za-z0-9_]*=.*/;
constant WRAPPER_COMMANDS (line 9) | const WRAPPER_COMMANDS = new Set(['sudo', 'env', 'time', 'command']);
constant EXECUTION_SHELL (line 10) | const EXECUTION_SHELL = getExecutionShell();
function sanitizeToken (line 12) | function sanitizeToken(token: string): string {
function extractCommandNames (line 16) | function extractCommandNames(command: string): string[] {
function findBlockedCommands (line 47) | function findBlockedCommands(command: string): string[] {
function isBlocked (line 66) | function isBlocked(command: string): boolean {
type CommandResult (line 71) | interface CommandResult {
function executeCommand (line 83) | async function executeCommand(
function executeCommandSync (line 118) | function executeCommandSync(
FILE: apps/cli/src/application/lib/exec-tool.ts
function execMcpTool (line 6) | async function execMcpTool(agentTool: z.infer<typeof ToolAttachment> & {...
function execTool (line 11) | async function execTool(agentTool: z.infer<typeof ToolAttachment>, input...
FILE: apps/cli/src/application/lib/id-gen.ts
type IMonotonicallyIncreasingIdGenerator (line 1) | interface IMonotonicallyIncreasingIdGenerator {
class IdGen (line 5) | class IdGen implements IMonotonicallyIncreasingIdGenerator {
method constructor (line 11) | constructor() {
method next (line 20) | async next(): Promise<string> {
FILE: apps/cli/src/application/lib/message-queue.ts
type IMessageQueue (line 9) | interface IMessageQueue {
class InMemoryMessageQueue (line 14) | class InMemoryMessageQueue implements IMessageQueue {
method constructor (line 18) | constructor({
method enqueue (line 26) | async enqueue(runId: string, message: string): Promise<string> {
method dequeue (line 38) | async dequeue(runId: string): Promise<z.infer<typeof EnqueuedMessage> ...
FILE: apps/cli/src/application/lib/random-id.ts
function randomId (line 5) | async function randomId(): Promise<string> {
FILE: apps/cli/src/application/lib/stream-renderer.ts
type StreamRendererOptions (line 5) | interface StreamRendererOptions {
class StreamRenderer (line 12) | class StreamRenderer {
method constructor (line 18) | constructor(options?: StreamRendererOptions) {
method render (line 28) | render(event: z.infer<typeof RunEvent>) {
method renderLlmEvent (line 57) | private renderLlmEvent(event: z.infer<typeof LlmStepStreamEvent>) {
method onStart (line 86) | private onStart(agentName: string, runId: string) {
method onEnd (line 93) | private onEnd() {
method onError (line 101) | private onError(error: string) {
method onStepStart (line 109) | private onStepStart() {
method onStepEnd (line 116) | private onStepEnd() {
method onStepMessage (line 121) | private onStepMessage(stepIndex: number, message: any) {
method onStepToolInvocation (line 133) | private onStepToolInvocation(toolName: string, input: string) {
method onStepToolResult (line 143) | private onStepToolResult(toolName: string, result: unknown) {
method onReasoningStart (line 152) | private onReasoningStart() {
method onReasoningDelta (line 162) | private onReasoningDelta(delta: string) {
method onReasoningEnd (line 167) | private onReasoningEnd() {
method onTextStart (line 173) | private onTextStart() {
method onTextDelta (line 188) | private onTextDelta(delta: string) {
method onTextEnd (line 198) | private onTextEnd() {
method onToolCall (line 204) | private onToolCall(toolCallId: string, toolName: string, input: unknow...
method onPauseForHumanInput (line 215) | private onPauseForHumanInput(toolCallId: string, question: string) {
method onFinishStep (line 222) | private onFinishStep(
method write (line 251) | private write(text: string) {
method indent (line 255) | private indent(text: string): string {
method truncate (line 262) | private truncate(text: string): string {
method bold (line 267) | private bold(text: string): string {
method dim (line 271) | private dim(text: string): string {
method italic (line 275) | private italic(text: string): string {
method cyan (line 279) | private cyan(text: string): string {
method green (line 283) | private green(text: string): string {
method red (line 287) | private red(text: string): string {
method magenta (line 291) | private magenta(text: string): string {
method yellow (line 295) | private yellow(text: string): string {
method neutral (line 299) | private neutral(text: string): string {
FILE: apps/cli/src/config/config.ts
function ensureDirs (line 8) | function ensureDirs() {
FILE: apps/cli/src/config/security.ts
constant SECURITY_CONFIG_PATH (line 5) | const SECURITY_CONFIG_PATH = path.join(WorkDir, "config", "security.json");
constant DEFAULT_ALLOW_LIST (line 7) | const DEFAULT_ALLOW_LIST = [
function ensureSecurityConfig (line 23) | function ensureSecurityConfig() {
function normalizeList (line 33) | function normalizeList(commands: unknown[]): string[] {
function parseSecurityPayload (line 45) | function parseSecurityPayload(payload: unknown): string[] {
function readAllowList (line 66) | function readAllowList(): string[] {
function getSecurityAllowList (line 79) | function getSecurityAllowList(): string[] {
function resetSecurityAllowListCache (line 98) | function resetSecurityAllowListCache() {
FILE: apps/cli/src/knowledge/sync_calendar.ts
constant CREDENTIALS_PATH (line 9) | const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json');
constant TOKEN_PATH (line 10) | const TOKEN_PATH = path.join(process.cwd(), 'token_calendar_notes.json');
constant SYNC_INTERVAL_MS (line 11) | const SYNC_INTERVAL_MS = 60 * 1000;
constant SCOPES (line 12) | const SCOPES = [
function loadSavedCredentialsIfExist (line 21) | async function loadSavedCredentialsIfExist(): Promise<OAuth2Client | nul...
function saveCredentials (line 51) | async function saveCredentials(client: OAuth2Client) {
function authorize (line 66) | async function authorize(): Promise<OAuth2Client> {
function cleanFilename (line 98) | function cleanFilename(name: string): string {
function cleanUpOldFiles (line 104) | function cleanUpOldFiles(currentEventIds: Set<string>, syncDir: string) {
function saveEvent (line 141) | async function saveEvent(event: any, syncDir: string): Promise<boolean> {
function processAttachments (line 156) | async function processAttachments(drive: any, event: any, syncDir: strin...
function syncCalendarWindow (line 208) | async function syncCalendarWindow(auth: OAuth2Client, syncDir: string, l...
function main (line 254) | async function main() {
FILE: apps/cli/src/knowledge/sync_gmail.ts
constant DEFAULT_SYNC_DIR (line 9) | const DEFAULT_SYNC_DIR = 'synced_emails_ts';
constant CREDENTIALS_PATH (line 10) | const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json');
constant TOKEN_PATH (line 11) | const TOKEN_PATH = path.join(process.cwd(), 'token_api.json');
constant SYNC_INTERVAL_MS (line 12) | const SYNC_INTERVAL_MS = 60 * 1000;
constant SCOPES (line 13) | const SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
function loadSavedCredentialsIfExist (line 19) | async function loadSavedCredentialsIfExist(): Promise<OAuth2Client | nul...
function saveCredentials (line 44) | async function saveCredentials(client: OAuth2Client) {
function authorize (line 59) | async function authorize(): Promise<OAuth2Client> {
function cleanFilename (line 92) | function cleanFilename(name: string): string {
function decodeBase64 (line 96) | function decodeBase64(data: string): string {
function getBody (line 100) | function getBody(payload: any): string {
function saveAttachment (line 131) | async function saveAttachment(gmail: any, userId: string, msgId: string,...
function processThread (line 162) | async function processThread(auth: OAuth2Client, threadId: string, syncD...
function loadState (line 225) | function loadState(stateFile: string): { historyId?: string } {
function saveState (line 232) | function saveState(historyId: string, stateFile: string) {
function fullSync (line 239) | async function fullSync(auth: OAuth2Client, syncDir: string, attachments...
function partialSync (line 272) | async function partialSync(auth: OAuth2Client, startHistoryId: string, s...
function main (line 326) | async function main() {
FILE: apps/cli/src/mcp/mcp.ts
type mcpState (line 16) | type mcpState = {
function getClient (line 23) | async function getClient(serverName: string): Promise<Client> {
function cleanup (line 80) | async function cleanup() {
function listServers (line 88) | async function listServers(): Promise<z.infer<typeof McpServerList>> {
function listTools (line 105) | async function listTools(serverName: string, cursor?: string): Promise<z...
function executeTool (line 116) | async function executeTool(serverName: string, toolName: string, input: ...
FILE: apps/cli/src/mcp/repo.ts
type IMcpConfigRepo (line 7) | interface IMcpConfigRepo {
class FSMcpConfigRepo (line 13) | class FSMcpConfigRepo implements IMcpConfigRepo {
method constructor (line 16) | constructor() {
method ensureDefaultConfig (line 20) | private async ensureDefaultConfig(): Promise<void> {
method getConfig (line 28) | async getConfig(): Promise<z.infer<typeof McpServerConfig>> {
method upsert (line 33) | async upsert(serverName: string, config: z.infer<typeof McpServerDefin...
method delete (line 39) | async delete(serverName: string): Promise<void> {
FILE: apps/cli/src/models/models.ts
function getProvider (line 41) | async function getProvider(name: string = ""): Promise<ProviderV2> {
FILE: apps/cli/src/models/repo.ts
type IModelConfigRepo (line 7) | interface IModelConfigRepo {
class FSModelConfigRepo (line 26) | class FSModelConfigRepo implements IModelConfigRepo {
method constructor (line 29) | constructor() {
method ensureDefaultConfig (line 33) | private async ensureDefaultConfig(): Promise<void> {
method getConfig (line 41) | async getConfig(): Promise<z.infer<typeof ModelConfig>> {
method setConfig (line 46) | private async setConfig(config: z.infer<typeof ModelConfig>): Promise<...
method upsert (line 50) | async upsert(providerName: string, config: z.infer<typeof Provider>): ...
method delete (line 56) | async delete(providerName: string): Promise<void> {
method setDefault (line 62) | async setDefault(providerName: string, model: string): Promise<void> {
FILE: apps/cli/src/runs/lock.ts
type IRunsLock (line 1) | interface IRunsLock {
class InMemoryRunsLock (line 6) | class InMemoryRunsLock implements IRunsLock {
method lock (line 9) | async lock(runId: string): Promise<boolean> {
method release (line 17) | async release(runId: string): Promise<void> {
FILE: apps/cli/src/runs/repo.ts
type IRunsRepo (line 22) | interface IRunsRepo {
class FSRunsRepo (line 29) | class FSRunsRepo implements IRunsRepo {
method constructor (line 31) | constructor({
method appendEvents (line 39) | async appendEvents(runId: string, events: z.infer<typeof RunEvent>[]):...
method create (line 46) | async create(options: z.infer<typeof CreateRunOptions>): Promise<z.inf...
method fetch (line 65) | async fetch(id: string): Promise<z.infer<typeof Run>> {
method list (line 81) | async list(cursor?: string): Promise<z.infer<typeof ListRunsResponse>> {
FILE: apps/cli/src/runs/runs.ts
function createRun (line 28) | async function createRun(opts: z.infer<typeof CreateRunOptions>): Promis...
function createMessage (line 36) | async function createMessage(runId: string, message: string): Promise<st...
function authorizePermission (line 44) | async function authorizePermission(runId: string, ev: z.infer<typeof Too...
function replyToHumanInputRequest (line 56) | async function replyToHumanInputRequest(runId: string, ev: z.infer<typeo...
function stop (line 68) | async function stop(runId: string): Promise<void> {
FILE: apps/cli/src/shared/prefix-logger.ts
class PrefixLogger (line 3) | class PrefixLogger {
method constructor (line 7) | constructor(prefix: string, parent: PrefixLogger | null = null) {
method log (line 12) | log(...args: any[]) {
method child (line 23) | child(childPrefix: string): PrefixLogger {
FILE: apps/cli/src/tui/api.ts
type RunEventType (line 21) | type RunEventType = z.infer<typeof RunEvent>;
type RowboatApiOptions (line 23) | interface RowboatApiOptions {
class RowboatApi (line 27) | class RowboatApi {
method constructor (line 29) | constructor({ baseUrl }: RowboatApiOptions = {}) {
method buildUrl (line 33) | private buildUrl(pathname: string): string {
method request (line 37) | private async request<T>(pathname: string, init?: RequestInit): Promis...
method getHealth (line 74) | async getHealth(): Promise<z.infer<typeof HealthSchema>> {
method getModelConfig (line 79) | async getModelConfig(): Promise<z.infer<typeof ModelConfig>> {
method listAgents (line 84) | async listAgents(): Promise<z.infer<typeof Agent>[]> {
method listRuns (line 89) | async listRuns(cursor?: string): Promise<z.infer<typeof ListRunsRespon...
method getRun (line 98) | async getRun(runId: string): Promise<z.infer<typeof Run>> {
method createRun (line 103) | async createRun(agentId: string): Promise<z.infer<typeof Run>> {
method sendMessage (line 111) | async sendMessage(runId: string, message: string): Promise<z.infer<typ...
method authorizeTool (line 119) | async authorizeTool(runId: string, payload: z.infer<typeof ToolPermiss...
method replyToHuman (line 127) | async replyToHuman(runId: string, requestId: string, payload: z.infer<...
method stopRun (line 135) | async stopRun(runId: string): Promise<void> {
method subscribeToEvents (line 142) | async subscribeToEvents(onEvent: (event: RunEventType) => void, onErro...
FILE: apps/cli/src/tui/index.tsx
function runTui (line 5) | function runTui({ serverUrl }: { serverUrl?: string }) {
FILE: apps/cli/src/tui/ui.tsx
type AgentType (line 14) | type AgentType = z.infer<typeof Agent>;
type ModelConfigType (line 15) | type ModelConfigType = z.infer<typeof ModelConfig>;
type RunSummary (line 16) | type RunSummary = z.infer<typeof ListRunsResponse>["runs"][number];
type RunType (line 17) | type RunType = z.infer<typeof Run>;
type RunEventType (line 18) | type RunEventType = z.infer<typeof RunEvent>;
type Toast (line 20) | type Toast = {
type ChatLine (line 25) | type ChatLine = {
type ModalState (line 31) | type ModalState =
type ConnectionState (line 43) | type ConnectionState = "connecting" | "ready" | "error";
type FocusTarget (line 44) | type FocusTarget = "chat" | "sidebar";
type PendingPermission (line 46) | type PendingPermission = {
type PendingHuman (line 53) | type PendingHuman = {
type SidebarItem (line 59) | type SidebarItem =
function RowboatTui (line 63) | function RowboatTui({ serverUrl }: { serverUrl: string }) {
function Header (line 715) | function Header({
function Sidebar (line 775) | function Sidebar({
function ChatPanel (line 838) | function ChatPanel({
function ModalSurface (line 924) | function ModalSurface({ children }: { children: React.ReactNode }) {
function AgentPickerModal (line 934) | function AgentPickerModal({
function MessageModal (line 963) | function MessageModal({
function derivePendingPermissions (line 1009) | function derivePendingPermissions(run: RunType | undefined): PendingPerm...
function derivePendingHuman (line 1035) | function derivePendingHuman(run: RunType | undefined): PendingHuman[] {
function getRunStatus (line 1057) | function getRunStatus(run: RunType | undefined): { label: string; color:...
function MessageBubble (line 1074) | function MessageBubble({ event }: { event: ChatLine }) {
function formatEvent (line 1094) | function formatEvent(event: RunEventType): ChatLine | null {
function truncate (line 1145) | function truncate(input: string, len = 60): string {
function formatTimestamp (line 1152) | function formatTimestamp(iso: string): string {
function timeAgo (line 1160) | function timeAgo(iso: string): string {
FILE: apps/experimental/chat_widget/app/api/bootstrap.js/route.ts
function GET (line 7) | async function GET() {
FILE: apps/experimental/chat_widget/app/app.tsx
type Message (line 9) | type Message = {
function ChatWindowHeader (line 16) | function ChatWindowHeader({
function LoadingAssistantResponse (line 57) | function LoadingAssistantResponse() {
function AssistantMessage (line 69) | function AssistantMessage({
function UserMessage (line 82) | function UserMessage({
function ChatWindowMessages (line 93) | function ChatWindowMessages({
function ChatWindowInput (line 131) | function ChatWindowInput({
function ChatWindowBody (line 162) | function ChatWindowBody({
function ChatWindow (line 212) | function ChatWindow({
function App (line 252) | function App({
FILE: apps/experimental/chat_widget/app/layout.tsx
function RootLayout (line 21) | function RootLayout({
FILE: apps/experimental/chat_widget/app/markdown-content.tsx
function MarkdownContent (line 4) | function MarkdownContent({ content }: { content: string }) {
FILE: apps/experimental/chat_widget/app/page.tsx
function Page (line 6) | function Page() {
FILE: apps/experimental/chat_widget/app/providers.tsx
function Providers (line 6) | function Providers({
FILE: apps/experimental/chat_widget/public/bootstrap.template.js
constant CONFIG (line 2) | const CONFIG = {
class SessionManager (line 33) | class SessionManager {
method createGuestSession (line 34) | static async createGuestSession() {
class CookieManager (line 57) | class CookieManager {
method getCookie (line 58) | static getCookie(name) {
method setCookie (line 65) | static setCookie(name, value) {
method deleteCookie (line 69) | static deleteCookie(name) {
class IframeManager (line 75) | class IframeManager {
method createIframe (line 76) | static createIframe(url, isMinimized) {
method updateSize (line 87) | static updateSize(iframe, isMinimized) {
method removeIframe (line 92) | static removeIframe(iframe) {
class ChatWidget (line 100) | class ChatWidget {
method constructor (line 101) | constructor() {
method init (line 112) | async init() {
method createAndMountIframe (line 123) | createAndMountIframe() {
method buildUrl (line 130) | buildUrl() {
method setupEventListeners (line 141) | setupEventListeners() {
method handleMessage (line 145) | handleMessage(event) {
method handleSessionExpired (line 153) | async handleSessionExpired() {
method handleStateChange (line 168) | handleStateChange(data) {
method getStoredMinimizedState (line 173) | getStoredMinimizedState() {
FILE: apps/experimental/simulation_runner/db.py
function get_db (line 22) | def get_db():
function get_collection (line 26) | def get_collection(collection_name: str):
function get_api_key (line 30) | def get_api_key(project_id: str):
function get_pending_run (line 45) | def get_pending_run() -> Optional[TestRun]:
function set_run_to_completed (line 70) | def set_run_to_completed(test_run: TestRun, aggregate: AggregateResults):
function update_run_heartbeat (line 86) | def update_run_heartbeat(run_id: str):
function mark_stale_jobs_as_failed (line 96) | def mark_stale_jobs_as_failed(threshold_minutes: int = 20) -> int:
function get_simulations_for_run (line 118) | def get_simulations_for_run(test_run: TestRun) -> list[TestSimulation]:
function get_scenario_by_id (line 145) | def get_scenario_by_id(scenario_id: str) -> TestScenario:
function write_test_result (line 166) | def write_test_result(result: TestResult):
FILE: apps/experimental/simulation_runner/scenario_types.py
class TestScenario (line 8) | class TestScenario(BaseModel):
class TestSimulation (line 17) | class TestSimulation(BaseModel):
class AggregateResults (line 27) | class AggregateResults(BaseModel):
class TestRun (line 32) | class TestRun(BaseModel):
class TestResult (line 44) | class TestResult(BaseModel):
FILE: apps/experimental/simulation_runner/service.py
class JobService (line 21) | class JobService:
method __init__ (line 22) | def __init__(self):
method poll_and_process_jobs (line 27) | async def poll_and_process_jobs(self, max_iterations: Optional[int] = ...
method process_run (line 48) | async def process_run(self, run: TestRun):
method fail_stale_runs_loop (line 85) | async def fail_stale_runs_loop(self):
method heartbeat_loop (line 95) | async def heartbeat_loop(self, run_id: str, stop_event: asyncio.Event):
method start (line 106) | def start(self):
FILE: apps/experimental/simulation_runner/simulation.py
function simulate_simulation (line 17) | async def simulate_simulation(
function simulate_simulations (line 140) | async def simulate_simulations(
FILE: apps/experimental/tools_webhook/app.py
function require_signed_request (line 21) | def require_signed_request(f):
function tool_call (line 71) | def tool_call():
FILE: apps/experimental/tools_webhook/function_map.py
function greet (line 9) | def greet(name: str, message: str):
function add (line 13) | def add(a: int, b: int):
function get_account_balance (line 17) | def get_account_balance(user_id: str):
FILE: apps/experimental/tools_webhook/tests/test_app.py
function client (line 8) | def client():
function test_tool_call_greet (line 18) | def test_tool_call_greet(client):
function test_tool_call_missing_params (line 50) | def test_tool_call_missing_params(client):
function test_tool_call_invalid_func (line 75) | def test_tool_call_invalid_func(client):
FILE: apps/experimental/tools_webhook/tests/test_tool_caller.py
function test_call_tool_greet (line 7) | def test_call_tool_greet():
function test_call_tool_add (line 12) | def test_call_tool_add():
function test_call_tool_missing_func (line 17) | def test_call_tool_missing_func():
function test_call_tool_missing_param (line 23) | def test_call_tool_missing_param():
function test_call_tool_unexpected_param (line 29) | def test_call_tool_unexpected_param():
function test_call_tool_type_conversion_error (line 36) | def test_call_tool_type_conversion_error():
FILE: apps/experimental/tools_webhook/tool_caller.py
function call_tool (line 8) | def call_tool(function_name: str, parameters: dict, functions_map: dict):
FILE: apps/python-sdk/src/rowboat/client.py
class Client (line 10) | class Client:
method __init__ (line 11) | def __init__(self, host: str, projectId: str, apiKey: str) -> None:
method _call_api (line 18) | def _call_api(
method run_turn (line 37) | def run_turn(
FILE: apps/python-sdk/src/rowboat/schema.py
class SystemMessage (line 4) | class SystemMessage(BaseModel):
class UserMessage (line 8) | class UserMessage(BaseModel):
class AssistantMessage (line 12) | class AssistantMessage(BaseModel):
class FunctionCall (line 18) | class FunctionCall(BaseModel):
class ToolCall (line 22) | class ToolCall(BaseModel):
class AssistantMessageWithToolCalls (line 27) | class AssistantMessageWithToolCalls(BaseModel):
class ToolMessage (line 33) | class ToolMessage(BaseModel):
class Turn (line 47) | class Turn(BaseModel):
class ApiRequest (line 51) | class ApiRequest(BaseModel):
class ApiResponse (line 56) | class ApiResponse(BaseModel):
FILE: apps/rowboat/app/actions/assistant-templates.actions.ts
function serializeTemplate (line 13) | function serializeTemplate(template: any) {
function serializeTemplates (line 17) | function serializeTemplates(templates: any[]) {
type ListResponse (line 41) | type ListResponse = { items: any[]; nextCursor: string | null };
function buildPrebuiltList (line 43) | function buildPrebuiltList(params: z.infer<typeof ListTemplatesSchema>):...
function listAssistantTemplates (line 75) | async function listAssistantTemplates(request: z.infer<typeof ListTempla...
function getAssistantTemplate (line 115) | async function getAssistantTemplate(templateId: string) {
function getAssistantTemplateCategories (line 152) | async function getAssistantTemplateCategories() {
function createAssistantTemplate (line 160) | async function createAssistantTemplate(data: z.infer<typeof CreateTempla...
function deleteAssistantTemplate (line 209) | async function deleteAssistantTemplate(id: string) {
function toggleTemplateLike (line 235) | async function toggleTemplateLike(id: string) {
function getCurrentUser (line 243) | async function getCurrentUser() {
function addLikeStatusToTemplates (line 249) | async function addLikeStatusToTemplates(templates: any[], userId: string) {
FILE: apps/rowboat/app/actions/auth.actions.ts
function authCheck (line 12) | async function authCheck(): Promise<z.infer<typeof User>> {
function updateUserEmail (line 33) | async function updateUserEmail(email: string) {
FILE: apps/rowboat/app/actions/billing.actions.ts
function getCustomer (line 25) | async function getCustomer(): Promise<z.infer<typeof Customer>> {
function authorizeUserAction (line 37) | async function authorizeUserAction(request: z.infer<typeof AuthorizeRequ...
function logUsage (line 47) | async function logUsage(request: z.infer<typeof LogUsageRequest>) {
function getCustomerPortalUrl (line 57) | async function getCustomerPortalUrl(returnUrl: string): Promise<string> {
function getPrices (line 66) | async function getPrices(): Promise<z.infer<typeof PricesResponse>> {
function updateSubscriptionPlan (line 75) | async function updateSubscriptionPlan(plan: z.infer<typeof SubscriptionP...
function getEligibleModels (line 86) | async function getEligibleModels(): Promise<z.infer<typeof ModelsRespons...
FILE: apps/rowboat/app/actions/composio.actions.ts
function listToolkits (line 48) | async function listToolkits(projectId: string, cursor: string | null = n...
function getToolkit (line 58) | async function getToolkit(projectId: string, toolkitSlug: string): Promi...
function listTools (line 68) | async function listTools(projectId: string, toolkitSlug: string, searchQ...
function createComposioManagedOauth2ConnectedAccount (line 80) | async function createComposioManagedOauth2ConnectedAccount(projectId: st...
function createCustomConnectedAccount (line 91) | async function createCustomConnectedAccount(projectId: string, request: ...
function syncConnectedAccount (line 103) | async function syncConnectedAccount(projectId: string, toolkitSlug: stri...
function deleteConnectedAccount (line 114) | async function deleteConnectedAccount(projectId: string, toolkitSlug: st...
function listComposioTriggerTypes (line 127) | async function listComposioTriggerTypes(toolkitSlug: string, cursor?: st...
function createComposioTriggerDeployment (line 136) | async function createComposioTriggerDeployment(request: {
function listComposioTriggerDeployments (line 157) | async function listComposioTriggerDeployments(request: {
function deleteComposioTriggerDeployment (line 174) | async function deleteComposioTriggerDeployment(request: {
function fetchComposioTriggerDeployment (line 189) | async function fetchComposioTriggerDeployment(request: { deploymentId: s...
FILE: apps/rowboat/app/actions/conversation.actions.ts
function listConversations (line 11) | async function listConversations(request: {
function fetchConversation (line 27) | async function fetchConversation(request: {
FILE: apps/rowboat/app/actions/copilot.actions.ts
function getCopilotResponseStream (line 25) | async function getCopilotResponseStream(
function getCopilotAgentInstructions (line 61) | async function getCopilotAgentInstructions(
FILE: apps/rowboat/app/actions/custom-mcp-server.actions.ts
type McpServerType (line 12) | type McpServerType = z.infer<typeof CustomMcpServer>;
function validateUrl (line 14) | function validateUrl(url: string): string {
function addServer (line 29) | async function addServer(projectId: string, name: string, server: McpSer...
function removeServer (line 42) | async function removeServer(projectId: string, name: string): Promise<vo...
function fetchTools (line 52) | async function fetchTools(serverUrl: string, serverName: string): Promis...
FILE: apps/rowboat/app/actions/data-source.actions.ts
function getDataSource (line 33) | async function getDataSource(sourceId: string): Promise<z.infer<typeof D...
function listDataSources (line 43) | async function listDataSources(projectId: string): Promise<z.infer<typeo...
function createDataSource (line 53) | async function createDataSource({
function recrawlWebDataSource (line 80) | async function recrawlWebDataSource(sourceId: string) {
function deleteDataSource (line 90) | async function deleteDataSource(sourceId: string) {
function toggleDataSource (line 100) | async function toggleDataSource(sourceId: string, active: boolean) {
function addDocsToDataSource (line 111) | async function addDocsToDataSource({
function listDocsInDataSource (line 131) | async function listDocsInDataSource({
function deleteDocFromDataSource (line 157) | async function deleteDocFromDataSource({
function getDownloadUrlForFile (line 170) | async function getDownloadUrlForFile(
function getUploadUrlsForFilesDataSource (line 182) | async function getUploadUrlsForFilesDataSource(
function updateDataSource (line 200) | async function updateDataSource({
FILE: apps/rowboat/app/actions/job.actions.ts
function listJobs (line 13) | async function listJobs(request: {
function fetchJob (line 31) | async function fetchJob(request: {
FILE: apps/rowboat/app/actions/playground-chat.actions.ts
function createConversation (line 11) | async function createConversation({
function createCachedTurn (line 32) | async function createCachedTurn({
FILE: apps/rowboat/app/actions/project.actions.ts
function listTemplates (line 43) | async function listTemplates() {
function projectAuthCheck (line 57) | async function projectAuthCheck(projectId: string) {
function createProject (line 69) | async function createProject(formData: FormData): Promise<{ id: string }...
function createProjectFromWorkflowJson (line 94) | async function createProjectFromWorkflowJson(formData: FormData): Promis...
function fetchProject (line 131) | async function fetchProject(projectId: string): Promise<z.infer<typeof P...
function listProjects (line 146) | async function listProjects(): Promise<z.infer<typeof Project>[]> {
function rotateSecret (line 163) | async function rotateSecret(projectId: string): Promise<string> {
function updateWebhookUrl (line 172) | async function updateWebhookUrl(projectId: string, url: string) {
function createApiKey (line 182) | async function createApiKey(projectId: string): Promise<z.infer<typeof A...
function deleteApiKey (line 191) | async function deleteApiKey(projectId: string, id: string) {
function listApiKeys (line 201) | async function listApiKeys(projectId: string): Promise<z.infer<typeof Ap...
function updateProjectName (line 210) | async function updateProjectName(projectId: string, name: string) {
function deleteProject (line 220) | async function deleteProject(projectId: string) {
function saveWorkflow (line 231) | async function saveWorkflow(projectId: string, workflow: z.infer<typeof ...
function publishWorkflow (line 241) | async function publishWorkflow(projectId: string, workflow: z.infer<type...
function revertToLiveWorkflow (line 251) | async function revertToLiveWorkflow(projectId: string) {
FILE: apps/rowboat/app/actions/recurring-job-rules.actions.ts
function createRecurringJobRule (line 21) | async function createRecurringJobRule(request: {
function listRecurringJobRules (line 39) | async function listRecurringJobRules(request: {
function fetchRecurringJobRule (line 55) | async function fetchRecurringJobRule(request: {
function toggleRecurringJobRule (line 67) | async function toggleRecurringJobRule(request: {
function deleteRecurringJobRule (line 81) | async function deleteRecurringJobRule(request: {
function updateRecurringJobRule (line 95) | async function updateRecurringJobRule(request: {
FILE: apps/rowboat/app/actions/scheduled-job-rules.actions.ts
function createScheduledJobRule (line 19) | async function createScheduledJobRule(request: {
function listScheduledJobRules (line 37) | async function listScheduledJobRules(request: {
function fetchScheduledJobRule (line 53) | async function fetchScheduledJobRule(request: {
function deleteScheduledJobRule (line 65) | async function deleteScheduledJobRule(request: {
function updateScheduledJobRule (line 79) | async function updateScheduledJobRule(request: {
FILE: apps/rowboat/app/actions/shared-workflow.actions.ts
constant DEFAULT_TTL_SECONDS (line 10) | const DEFAULT_TTL_SECONDS = 60 * 60 * 24;
type SharedWorkflowDoc (line 12) | interface SharedWorkflowDoc {
function validateWorkflowJson (line 19) | function validateWorkflowJson(obj: unknown) {
function createSharedWorkflowFromJson (line 28) | async function createSharedWorkflowFromJson(json: string): Promise<{ id:...
function loadSharedWorkflow (line 48) | async function loadSharedWorkflow(id: string): Promise<z.infer<typeof Wo...
FILE: apps/rowboat/app/actions/twilio.actions.ts
function serializeConfig (line 13) | function serializeConfig(config: any) {
function configureTwilioNumber (line 22) | async function configureTwilioNumber(params: z.infer<typeof TwilioConfig...
function saveTwilioConfig (line 63) | async function saveTwilioConfig(params: z.infer<typeof TwilioConfigParam...
function getTwilioConfigs (line 145) | async function getTwilioConfigs(projectId: string): Promise<WithStringId...
function deleteTwilioConfig (line 164) | async function deleteTwilioConfig(projectId: string, configId: string) {
function mockConfigureTwilioNumber (line 181) | async function mockConfigureTwilioNumber(params: z.infer<typeof TwilioCo...
function configureInboundCall (line 187) | async function configureInboundCall(
FILE: apps/rowboat/app/api/composio/webhook/route.ts
function POST (line 8) | async function POST(request: Request) {
FILE: apps/rowboat/app/api/copilot-stream-response/[streamId]/route.ts
function GET (line 7) | async function GET(request: Request, props: { params: Promise<{ streamId...
FILE: apps/rowboat/app/api/generated-images/[id]/route.ts
function GET (line 7) | async function GET(request: NextRequest, props: { params: Promise<{ id: ...
FILE: apps/rowboat/app/api/me/route.ts
function GET (line 5) | async function GET(_req: NextRequest) {
FILE: apps/rowboat/app/api/stream-response/[streamId]/route.ts
function GET (line 9) | async function GET(request: Request, props: { params: Promise<{ streamId...
FILE: apps/rowboat/app/api/tmp-images/[id]/route.ts
function GET (line 4) | async function GET(request: NextRequest, props: { params: Promise<{ id: ...
FILE: apps/rowboat/app/api/twilio/inbound_call/route.ts
function POST (line 42) | async function POST(request: Request) {
FILE: apps/rowboat/app/api/twilio/turn/[callSid]/route.ts
function POST (line 14) | async function POST(
FILE: apps/rowboat/app/api/twilio/utils.ts
function XmlResponse (line 5) | function XmlResponse(content: TwiML) {
function reject (line 13) | function reject(reason: VoiceResponse.RejectAttributes['reason']) {
function hangup (line 21) | function hangup() {
FILE: apps/rowboat/app/api/uploads/[fileId]/route.ts
constant UPLOADS_DIR (line 8) | const UPLOADS_DIR = process.env.RAG_UPLOADS_DIR || '/uploads';
function PUT (line 13) | async function PUT(request: NextRequest, props: { params: Promise<{ file...
function GET (line 37) | async function GET(request: NextRequest, props: { params: Promise<{ file...
FILE: apps/rowboat/app/api/v1/[projectId]/chat/route.ts
function POST (line 10) | async function POST(
FILE: apps/rowboat/app/api/widget/v1/chats/[chatId]/close/route.ts
function POST (line 6) | async function POST(request: NextRequest, props: { params: Promise<{ cha...
FILE: apps/rowboat/app/api/widget/v1/chats/[chatId]/messages/route.ts
function GET (line 9) | async function GET(req: NextRequest, props: { params: Promise<{ chatId: ...
FILE: apps/rowboat/app/api/widget/v1/chats/[chatId]/route.ts
function GET (line 11) | async function GET(
FILE: apps/rowboat/app/api/widget/v1/chats/[chatId]/turn/route.ts
function convert (line 15) | function convert(messages: z.infer<typeof apiV1.ChatMessage>[]): z.infer...
function convertBack (line 63) | function convertBack(messages: z.infer<typeof AssistantMessage | typeof ...
function POST (line 111) | async function POST(
FILE: apps/rowboat/app/api/widget/v1/chats/route.ts
function POST (line 11) | async function POST(
function GET (line 54) | async function GET(
FILE: apps/rowboat/app/api/widget/v1/session/guest/route.ts
function POST (line 8) | async function POST(req: NextRequest): Promise<Response> {
FILE: apps/rowboat/app/api/widget/v1/session/user/route.ts
function POST (line 8) | async function POST(req: NextRequest): Promise<Response> {
FILE: apps/rowboat/app/api/widget/v1/utils.ts
function clientIdCheck (line 19) | async function clientIdCheck(req: NextRequest, handler: (projectId: stri...
function authCheck (line 46) | async function authCheck(req: NextRequest, handler: (session: z.infer<ty...
FILE: apps/rowboat/app/app.tsx
function App (line 8) | function App() {
FILE: apps/rowboat/app/billing/app.tsx
type BillingPageProps (line 32) | interface BillingPageProps {
function getDisplayStatus (line 37) | function getDisplayStatus(status: string | undefined) {
function BillingPage (line 47) | function BillingPage({ customer, usage }: BillingPageProps) {
FILE: apps/rowboat/app/billing/callback/page.tsx
function Page (line 7) | async function Page(
FILE: apps/rowboat/app/billing/layout.tsx
function Layout (line 3) | function Layout({
FILE: apps/rowboat/app/billing/page.tsx
function Page (line 9) | async function Page() {
FILE: apps/rowboat/app/components/ui/textarea-with-send.tsx
type TextareaWithSendProps (line 9) | interface TextareaWithSendProps extends Omit<TextareaHTMLAttributes<HTML...
FILE: apps/rowboat/app/composio/oauth2/callback/page.tsx
function OAuth2CallbackPage (line 6) | function OAuth2CallbackPage() {
FILE: apps/rowboat/app/layout.tsx
function RootLayout (line 18) | function RootLayout({
FILE: apps/rowboat/app/lib/assistant_templates_seed.ts
function ensureLibraryTemplatesSeeded (line 9) | async function ensureLibraryTemplatesSeeded(): Promise<void> {
function ensureTemplateSeeded (line 117) | async function ensureTemplateSeeded(prebuiltKey: string): Promise<void> {
FILE: apps/rowboat/app/lib/auth.ts
constant GUEST_SESSION (line 9) | const GUEST_SESSION = {
constant GUEST_DB_USER (line 15) | const GUEST_DB_USER: z.infer<typeof User> = {
function requireAuth (line 35) | async function requireAuth(): Promise<z.infer<typeof User>> {
function getUserFromSessionId (line 61) | async function getUserFromSessionId(sessionUserId: string): Promise<z.in...
FILE: apps/rowboat/app/lib/billing.ts
constant BILLING_API_URL (line 10) | const BILLING_API_URL = process.env.BILLING_API_URL || 'http://billing';
constant BILLING_API_KEY (line 11) | const BILLING_API_KEY = process.env.BILLING_API_KEY || 'test';
constant GUEST_BILLING_CUSTOMER (line 15) | const GUEST_BILLING_CUSTOMER = {
class UsageTracker (line 28) | class UsageTracker{
method track (line 31) | track(item: z.infer<typeof UsageItem>) {
method flush (line 35) | flush(): z.infer<typeof UsageItem>[] {
function getCustomerForUserId (line 42) | async function getCustomerForUserId(userId: string): Promise<z.infer<typ...
function getCustomerIdForProject (line 55) | async function getCustomerIdForProject(projectId: string): Promise<strin...
function getBillingCustomer (line 68) | async function getBillingCustomer(id: string): Promise<z.infer<typeof Cu...
function createBillingCustomer (line 87) | async function createBillingCustomer(userId: string, email: string): Pro...
function syncWithStripe (line 107) | async function syncWithStripe(customerId: string): Promise<void> {
function authorize (line 120) | async function authorize(customerId: string, request: z.infer<typeof Aut...
function logUsage (line 140) | async function logUsage(customerId: string, request: z.infer<typeof LogU...
function getUsage (line 157) | async function getUsage(customerId: string): Promise<z.infer<typeof Usag...
function createCustomerPortalSession (line 176) | async function createCustomerPortalSession(customerId: string, returnUrl...
function getPrices (line 196) | async function getPrices(): Promise<z.infer<typeof PricesResponse>> {
function updateSubscriptionPlan (line 215) | async function updateSubscriptionPlan(customerId: string, request: z.inf...
function getEligibleModels (line 235) | async function getEligibleModels(customerId: string): Promise<z.infer<ty...
function requireBillingCustomer (line 267) | async function requireBillingCustomer(): Promise<z.infer<typeof Customer...
function requireActiveBillingSubscription (line 313) | async function requireActiveBillingSubscription(): Promise<z.infer<typeo...
FILE: apps/rowboat/app/lib/client_utils.ts
function validateConfigChanges (line 7) | function validateConfigChanges(configType: string, configChanges: Record...
FILE: apps/rowboat/app/lib/components/atmentions.ts
type AtMentionItem (line 1) | interface AtMentionItem {
type CreateAtMentionsProps (line 7) | interface CreateAtMentionsProps {
function createAtMentions (line 16) | function createAtMentions({ agents, prompts, tools, pipelines = [], curr...
FILE: apps/rowboat/app/lib/components/datasource-icon.tsx
function DataSourceIcon (line 3) | function DataSourceIcon({
FILE: apps/rowboat/app/lib/components/dropdown.tsx
type DropdownOption (line 4) | interface DropdownOption {
type DropdownProps (line 9) | interface DropdownProps {
function Dropdown (line 17) | function Dropdown({
FILE: apps/rowboat/app/lib/components/form-section.tsx
function FormSection (line 4) | function FormSection({
FILE: apps/rowboat/app/lib/components/form-status-button-old.tsx
function FormStatusButton (line 6) | function FormStatusButton({
FILE: apps/rowboat/app/lib/components/form-status-button.tsx
function FormStatusButton (line 7) | function FormStatusButton({
FILE: apps/rowboat/app/lib/components/icons.tsx
function WorkflowIcon (line 1) | function WorkflowIcon({
function HamburgerIcon (line 15) | function HamburgerIcon({
function BackIcon (line 29) | function BackIcon({
FILE: apps/rowboat/app/lib/components/input-field.tsx
type BaseInputFieldProps (line 16) | interface BaseInputFieldProps {
type TextInputFieldProps (line 35) | interface TextInputFieldProps extends BaseInputFieldProps {
type SelectInputFieldProps (line 48) | interface SelectInputFieldProps extends BaseInputFieldProps {
type CheckboxInputFieldProps (line 56) | interface CheckboxInputFieldProps extends BaseInputFieldProps {
type NumberInputFieldProps (line 63) | interface NumberInputFieldProps extends BaseInputFieldProps {
type InputFieldProps (line 72) | type InputFieldProps = TextInputFieldProps | SelectInputFieldProps | Che...
function InputField (line 74) | function InputField(props: InputFieldProps) {
function TextInputField (line 93) | function TextInputField({
function SelectInputField (line 393) | function SelectInputField({
function CheckboxInputField (line 433) | function CheckboxInputField({
function NumberInputField (line 456) | function NumberInputField({
FILE: apps/rowboat/app/lib/components/label.tsx
function Label (line 1) | function Label({ label }: { label: string }) {
FILE: apps/rowboat/app/lib/components/markdown-content.tsx
function MarkdownContent (line 5) | function MarkdownContent({
FILE: apps/rowboat/app/lib/components/mentions_editor.tsx
type Match (line 10) | type Match = {
class CustomMentionBlot (line 18) | class CustomMentionBlot extends MentionBlot {
method render (line 19) | static render(data: any) {
function markdownToParts (line 30) | function markdownToParts(markdown: string, atValues: Match[]): (string |...
function insertPartsIntoQuill (line 67) | function insertPartsIntoQuill(quill: Quill, parts: (string | Match)[]) {
function MentionEditor (line 85) | function MentionEditor({
FILE: apps/rowboat/app/lib/components/menu-item.tsx
type MenuItemProps (line 4) | interface MenuItemProps {
FILE: apps/rowboat/app/lib/components/message-display.tsx
function ToolCallDisplay (line 7) | function ToolCallDisplay({ toolCall }: { toolCall: any }) {
function MessageDisplay (line 30) | function MessageDisplay({ message, index }: { message: z.infer<typeof Me...
FILE: apps/rowboat/app/lib/components/page-section.tsx
function PageSection (line 1) | function PageSection({
FILE: apps/rowboat/app/lib/components/pagination.tsx
function Pagination (line 6) | function Pagination({
FILE: apps/rowboat/app/lib/components/reason-badge.tsx
function ReasonBadge (line 5) | function ReasonBadge({
FILE: apps/rowboat/app/lib/components/structured-list.tsx
function SectionHeader (line 4) | function SectionHeader({ title, children }: { title: string; children: R...
function ListItem (line 15) | function ListItem({
FILE: apps/rowboat/app/lib/components/structured-panel.tsx
function ActionButton (line 5) | function ActionButton({
function StructuredPanel (line 32) | function StructuredPanel({
FILE: apps/rowboat/app/lib/components/typewriter.tsx
function TypewriterEffect (line 13) | function TypewriterEffect() {
FILE: apps/rowboat/app/lib/components/user_button.tsx
function UserButton (line 6) | function UserButton({ useBilling, collapsed }: { useBilling?: boolean, c...
FILE: apps/rowboat/app/lib/default_tools.ts
function getDefaultTools (line 8) | function getDefaultTools(): Array<any> {
FILE: apps/rowboat/app/lib/embedding.ts
constant EMBEDDING_PROVIDER_API_KEY (line 3) | const EMBEDDING_PROVIDER_API_KEY = process.env.EMBEDDING_PROVIDER_API_KE...
constant EMBEDDING_PROVIDER_BASE_URL (line 4) | const EMBEDDING_PROVIDER_BASE_URL = process.env.EMBEDDING_PROVIDER_BASE_...
constant EMBEDDING_MODEL (line 5) | const EMBEDDING_MODEL = process.env.EMBEDDING_MODEL || 'text-embedding-3...
FILE: apps/rowboat/app/lib/feature_flags.ts
constant USE_RAG (line 1) | const USE_RAG = process.env.USE_RAG === 'true';
constant USE_RAG_UPLOADS (line 2) | const USE_RAG_UPLOADS = process.env.USE_RAG_UPLOADS === 'true';
constant USE_RAG_SCRAPING (line 3) | const USE_RAG_SCRAPING = process.env.USE_RAG_SCRAPING === 'true';
constant USE_CHAT_WIDGET (line 4) | const USE_CHAT_WIDGET = process.env.USE_CHAT_WIDGET === 'true';
constant USE_AUTH (line 5) | const USE_AUTH = process.env.USE_AUTH === 'true';
constant USE_RAG_S3_UPLOADS (line 6) | const USE_RAG_S3_UPLOADS = process.env.USE_RAG_S3_UPLOADS === 'true';
constant USE_GEMINI_FILE_PARSING (line 7) | const USE_GEMINI_FILE_PARSING = process.env.USE_GEMINI_FILE_PARSING === ...
constant USE_BILLING (line 8) | const USE_BILLING = process.env.NEXT_PUBLIC_USE_BILLING === 'true' || pr...
constant USE_COMPOSIO_TOOLS (line 9) | const USE_COMPOSIO_TOOLS = process.env.USE_COMPOSIO_TOOLS === 'true';
constant USE_KLAVIS_TOOLS (line 10) | const USE_KLAVIS_TOOLS = process.env.USE_KLAVIS_TOOLS === 'false';
constant USE_MULTIPLE_PROJECTS (line 13) | const USE_MULTIPLE_PROJECTS = true;
constant USE_VOICE_FEATURE (line 14) | const USE_VOICE_FEATURE = false;
constant USE_TRANSFER_CONTROL_OPTIONS (line 15) | const USE_TRANSFER_CONTROL_OPTIONS = false;
constant USE_PRODUCT_TOUR (line 16) | const USE_PRODUCT_TOUR = false;
constant SHOW_COPILOT_MARQUEE (line 17) | const SHOW_COPILOT_MARQUEE = false;
constant SHOW_PROMPTS_SECTION (line 18) | const SHOW_PROMPTS_SECTION = true;
constant SHOW_DARK_MODE_TOGGLE (line 19) | const SHOW_DARK_MODE_TOGGLE = false;
constant SHOW_VISUALIZATION (line 20) | const SHOW_VISUALIZATION = false;
constant SHOW_COMMUNITY_PUBLISH (line 23) | const SHOW_COMMUNITY_PUBLISH = false;
FILE: apps/rowboat/app/lib/mcp.ts
function getMcpClient (line 6) | async function getMcpClient(serverUrl: string, serverName: string): Prom...
FILE: apps/rowboat/app/lib/types/types.ts
type WithStringId (line 139) | type WithStringId<T> = T & { _id: string };
function convertMcpServerToolToWorkflowTool (line 142) | function convertMcpServerToolToWorkflowTool(
FILE: apps/rowboat/app/lib/types/voice_types.ts
type TwilioConfigResponse (line 17) | interface TwilioConfigResponse {
type InboundConfigResponse (line 22) | interface InboundConfigResponse {
FILE: apps/rowboat/app/lib/types/workflow_types.ts
function sanitizeTextWithMentions (line 121) | function sanitizeTextWithMentions(
FILE: apps/rowboat/app/lib/utils.ts
class PrefixLogger (line 3) | class PrefixLogger {
method constructor (line 7) | constructor(prefix: string, parent: PrefixLogger | null = null) {
method log (line 12) | log(...args: any[]) {
method child (line 23) | child(childPrefix: string): PrefixLogger {
FILE: apps/rowboat/app/loading.tsx
function Loading (line 4) | function Loading() {
FILE: apps/rowboat/app/new-chat-link.tsx
function NewChatLink (line 3) | function NewChatLink({demo}: {demo: string}) {
FILE: apps/rowboat/app/onboarding/app.tsx
function App (line 12) | function App() {
FILE: apps/rowboat/app/onboarding/layout.tsx
function Layout (line 3) | function Layout({
FILE: apps/rowboat/app/onboarding/page.tsx
function Page (line 8) | async function Page() {
FILE: apps/rowboat/app/page.tsx
function Home (line 7) | function Home() {
FILE: apps/rowboat/app/projects/[projectId]/config/app.tsx
function Section (line 20) | function Section({
function SectionRow (line 33) | function SectionRow({
function LeftLabel (line 41) | function LeftLabel({
function RightContent (line 49) | function RightContent({
function BasicSettingsSection (line 57) | function BasicSettingsSection({
function SecretSection (line 107) | function SecretSection({
function WebhookUrlSection (line 184) | function WebhookUrlSection({
function DeleteProjectSection (line 288) | function DeleteProjectSection({
function ApiKeyDisplay (line 376) | function ApiKeyDisplay({ apiKey }: { apiKey: string }) {
function ConfigApp (line 407) | function ConfigApp({
function SimpleConfigApp (line 429) | function SimpleConfigApp({
FILE: apps/rowboat/app/projects/[projectId]/config/components/project.tsx
function Section (line 24) | function Section({
function SectionRow (line 46) | function SectionRow({
function LeftLabel (line 54) | function LeftLabel({
function RightContent (line 62) | function RightContent({
function ProjectNameSection (line 70) | function ProjectNameSection({
function ProjectIdSection (line 117) | function ProjectIdSection({ projectId }: { projectId: string }) {
function SecretSection (line 133) | function SecretSection({ projectId }: { projectId: string }) {
function ApiKeyDisplay (line 202) | function ApiKeyDisplay({ apiKey, onDelete }: { apiKey: string; onDelete:...
function ApiKeysSection (line 232) | function ApiKeysSection({ projectId }: { projectId: string }) {
type ConnectedToolkit (line 419) | interface ConnectedToolkit {
function DisconnectToolkitsSection (line 426) | function DisconnectToolkitsSection({ projectId, onProjectConfigUpdated }: {
function DeleteProjectSection (line 685) | function DeleteProjectSection({ projectId }: { projectId: string }) {
function ProjectSection (line 793) | function ProjectSection({
function SimpleProjectSection (line 811) | function SimpleProjectSection({
FILE: apps/rowboat/app/projects/[projectId]/config/components/voice.tsx
function PhoneNumberSection (line 15) | function PhoneNumberSection({
function AccountSidSection (line 48) | function AccountSidSection({
function AuthTokenSection (line 81) | function AuthTokenSection({
function LabelSection (line 114) | function LabelSection({
function VoiceSection (line 147) | function VoiceSection({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/config/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/conversations/[conversationId]/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/conversations/components/conversation-view.tsx
function TurnContainer (line 14) | function TurnContainer({ turn, index, projectId }: { turn: z.infer<typeo...
function ConversationView (line 78) | function ConversationView({ projectId, conversationId }: { projectId: st...
FILE: apps/rowboat/app/projects/[projectId]/conversations/components/conversations-list.tsx
type ListedItem (line 13) | type ListedItem = z.infer<typeof ListedConversationItem>;
function ConversationsList (line 15) | function ConversationsList({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/conversations/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/copilot/app.tsx
function getAppliedChangeKey (line 26) | function getAppliedChangeKey(messageIndex: number, actionIndex: number, ...
type AppProps (line 30) | interface AppProps {
function handleNewChat (line 358) | function handleNewChat() {
function handleCopyJson (line 363) | function handleCopyJson(data: { messages: any[] }) {
FILE: apps/rowboat/app/projects/[projectId]/copilot/components/TriggerSetupModal.tsx
type TriggerSetupModalProps (line 17) | interface TriggerSetupModalProps {
type Toolkit (line 27) | type Toolkit = z.infer<typeof ZToolkit>;
type TriggerType (line 28) | type TriggerType = z.infer<typeof ComposioTriggerType>;
type ProjectConfig (line 29) | type ProjectConfig = z.infer<typeof Project>;
function TriggerSetupModal (line 31) | function TriggerSetupModal({
FILE: apps/rowboat/app/projects/[projectId]/copilot/components/actions.tsx
function Action (line 22) | function Action({
function ActionSummary (line 259) | function ActionSummary() {
function ActionHeader (line 270) | function ActionHeader() {
function ActionField (line 284) | function ActionField({
function StreamingAction (line 383) | function StreamingAction({
FILE: apps/rowboat/app/projects/[projectId]/copilot/components/messages.tsx
type CopilotTriggerType (line 16) | type CopilotTriggerType = z.infer<typeof TriggerSchemaForCopilot>;
function enrich (line 33) | function enrich(response: string): z.infer<typeof CopilotResponsePart> {
function UserMessage (line 125) | function UserMessage({ content }: { content: string }) {
function InternalAssistantMessage (line 141) | function InternalAssistantMessage({ content }: { content: string }) {
function AssistantMessage (line 184) | function AssistantMessage({
function AssistantMessageLoading (line 578) | function AssistantMessageLoading({ currentStatus }: { currentStatus: 'th...
function Messages (line 598) | function Messages({
FILE: apps/rowboat/app/projects/[projectId]/copilot/components/use-trigger-actions.ts
type ScheduledJobActionsModule (line 8) | type ScheduledJobActionsModule = typeof import('@/app/actions/scheduled-...
type RecurringJobActionsModule (line 9) | type RecurringJobActionsModule = typeof import('@/app/actions/recurring-...
type ComposioActionsModule (line 10) | type ComposioActionsModule = typeof import('@/app/actions/composio.actio...
type CopilotTrigger (line 12) | type CopilotTrigger = z.infer<typeof TriggerSchemaForCopilot>;
type CopilotAction (line 13) | type CopilotAction = z.infer<typeof CopilotAssistantMessageActionPart>['...
type TriggerSetupModalState (line 15) | interface TriggerSetupModalState {
type UseCopilotTriggerActionsParams (line 24) | interface UseCopilotTriggerActionsParams {
type UseCopilotTriggerActionsResult (line 31) | interface UseCopilotTriggerActionsResult {
function loadScheduledJobActions (line 43) | function loadScheduledJobActions(): Promise<ScheduledJobActionsModule> {
function loadRecurringJobActions (line 50) | function loadRecurringJobActions(): Promise<RecurringJobActionsModule> {
function loadComposioActions (line 57) | function loadComposioActions(): Promise<ComposioActionsModule> {
type TriggerInput (line 88) | type TriggerInput = z.infer<typeof TriggerInputSchema>;
function useCopilotTriggerActions (line 123) | function useCopilotTriggerActions({
FILE: apps/rowboat/app/projects/[projectId]/copilot/use-copilot.tsx
type UseCopilotParams (line 10) | interface UseCopilotParams {
type UseCopilotResult (line 18) | interface UseCopilotResult {
function useCopilot (line 34) | function useCopilot({ projectId, workflow, context, dataSources, trigger...
FILE: apps/rowboat/app/projects/[projectId]/copilot/use-parsed-blocks.tsx
type Block (line 3) | type Block =
function parseMarkdown (line 9) | function parseMarkdown(markdown: string): Block[] {
function useParsedBlocks (line 26) | function useParsedBlocks(text: string): Block[] {
FILE: apps/rowboat/app/projects/[projectId]/entities/AgentGraphVisualizer.tsx
function sanitizeId (line 7) | function sanitizeId(name: string): string {
function generateMermaidFromWorkflow (line 11) | function generateMermaidFromWorkflow(workflow: any, isDark: boolean): st...
function getCssVarValue (line 121) | function getCssVarValue(varName: string, fallback: string) {
FILE: apps/rowboat/app/projects/[projectId]/entities/agent_config.tsx
type TabType (line 34) | type TabType = 'instructions' | 'configurations';
function AgentConfig (line 36) | function AgentConfig({
function GenerateInstructionsModal (line 750) | function GenerateInstructionsModal({
function validateAgentName (line 893) | function validateAgentName(value: string, currentName?: string, usedName...
FILE: apps/rowboat/app/projects/[projectId]/entities/datasource_config.tsx
function DataSourceConfig (line 17) | function DataSourceConfig({
FILE: apps/rowboat/app/projects/[projectId]/entities/pipeline_config.tsx
function PipelineConfig (line 14) | function PipelineConfig({
FILE: apps/rowboat/app/projects/[projectId]/entities/prompt_config.tsx
function PromptConfig (line 20) | function PromptConfig({
FILE: apps/rowboat/app/projects/[projectId]/entities/tool_config.tsx
function ParameterConfig (line 28) | function ParameterConfig({
function ToolConfig (line 154) | function ToolConfig({
FILE: apps/rowboat/app/projects/[projectId]/jobs/[jobId]/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/jobs/components/job-view.tsx
function JobView (line 12) | function JobView({ projectId, jobId }: { projectId: string; jobId: strin...
FILE: apps/rowboat/app/projects/[projectId]/jobs/components/jobs-list.tsx
type ListedItem (line 12) | type ListedItem = z.infer<typeof ListedJobItem>;
type JobsListProps (line 14) | interface JobsListProps {
function JobsList (line 21) | function JobsList({ projectId, filters, showTitle = true, customTitle }:...
FILE: apps/rowboat/app/projects/[projectId]/jobs/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/layout.tsx
function Layout (line 1) | async function Layout({
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/components/composio-trigger-deployment-view.tsx
function ComposioTriggerDeploymentView (line 15) | function ComposioTriggerDeploymentView({ projectId, deploymentId }: { pr...
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/components/create-recurring-job-rule-form.tsx
type FormMessage (line 15) | type FormMessage = {
type BackButtonConfig (line 20) | type BackButtonConfig =
type FormSubmitPayload (line 24) | type FormSubmitPayload = {
type RecurringJobRuleFormBaseProps (line 29) | type RecurringJobRuleFormBaseProps = {
function RecurringJobRuleFormBase (line 84) | function RecurringJobRuleFormBase({
function CreateRecurringJobRuleForm (line 336) | function CreateRecurringJobRuleForm({
function EditRecurringJobRuleForm (line 376) | function EditRecurringJobRuleForm({
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/components/job-rules-tabs.tsx
function JobRulesTabs (line 10) | function JobRulesTabs({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/components/recurring-job-rule-view.tsx
function RecurringJobRuleView (line 16) | function RecurringJobRuleView({ projectId, ruleId }: { projectId: string...
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/components/recurring-job-rules-list.tsx
type ListedItem (line 14) | type ListedItem = z.infer<typeof ListedRecurringRuleItem>;
function RecurringJobRulesList (line 16) | function RecurringJobRulesList({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/components/triggers-tab.tsx
type TriggerDeployment (line 22) | type TriggerDeployment = z.infer<typeof ComposioTriggerDeployment>;
function TriggersTab (line 26) | function TriggersTab({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/recurring/[ruleId]/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/recurring/new/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/[ruleId]/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/create-scheduled-job-rule-form.tsx
type FormMessage (line 16) | type FormMessage = {
type BackButtonConfig (line 21) | type BackButtonConfig =
type FormSubmitPayload (line 25) | type FormSubmitPayload = {
type ScheduledJobRuleFormBaseProps (line 30) | type ScheduledJobRuleFormBaseProps = {
function ScheduledJobRuleFormBase (line 76) | function ScheduledJobRuleFormBase({
function CreateScheduledJobRuleForm (line 292) | function CreateScheduledJobRuleForm({ projectId, onBack, hasExistingTrig...
function EditScheduledJobRuleForm (line 333) | function EditScheduledJobRuleForm({
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/scheduled-job-rule-view.tsx
function ScheduledJobRuleView (line 16) | function ScheduledJobRuleView({ projectId, ruleId }: { projectId: string...
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/components/scheduled-job-rules-list.tsx
type ListedItem (line 14) | type ListedItem = z.infer<typeof ListedRuleItem>;
function ScheduledJobRulesList (line 16) | function ScheduledJobRulesList({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/scheduled/new/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/manage-triggers/triggers/[deploymentId]/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/page.tsx
function Page (line 4) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/playground/app.tsx
function App (line 12) | function App({
FILE: apps/rowboat/app/projects/[projectId]/playground/components/chat.tsx
function Chat (line 16) | function Chat({
FILE: apps/rowboat/app/projects/[projectId]/playground/components/feedback-modal.tsx
type FeedbackModalProps (line 5) | interface FeedbackModalProps {
function FeedbackModal (line 12) | function FeedbackModal({ isOpen, onClose, onSubmit, title = "Provide Fee...
FILE: apps/rowboat/app/projects/[projectId]/playground/components/messages.tsx
function UserMessage (line 14) | function UserMessage({ content }: { content: string }) {
function InternalAssistantMessage (line 34) | function InternalAssistantMessage({ content, sender, latency, delta, sho...
function AssistantMessage (line 145) | function AssistantMessage({
function TypingIndicator (line 232) | function TypingIndicator() {
function ToolCalls (line 246) | function ToolCalls({
function ToolCall (line 294) | function ToolCall({
function TransferToAgentToolCall (line 362) | function TransferToAgentToolCall({
function ClientToolCall (line 410) | function ClientToolCall({
function ExpandableContent (line 661) | function ExpandableContent({
type MessageActionsMenuProps (line 732) | type MessageActionsMenuProps = {
function MessageActionsMenu (line 747) | function MessageActionsMenu({
function Messages (line 791) | function Messages({
FILE: apps/rowboat/app/projects/[projectId]/playground/components/profile-context-box.tsx
type ProfileContextBoxProps (line 6) | interface ProfileContextBoxProps {
function ProfileContextBox (line 12) | function ProfileContextBox({
FILE: apps/rowboat/app/projects/[projectId]/playground/copilot-prompts.ts
constant FIX_WORKFLOW_PROMPT (line 1) | const FIX_WORKFLOW_PROMPT = `There is an issue with this turn of chat (i...
constant FIX_WORKFLOW_PROMPT_WITH_FEEDBACK (line 5) | const FIX_WORKFLOW_PROMPT_WITH_FEEDBACK = `There is an issue with this t...
constant EXPLAIN_WORKFLOW_PROMPT_ASSISTANT (line 11) | const EXPLAIN_WORKFLOW_PROMPT_ASSISTANT = `Please explain why the assist...
constant EXPLAIN_WORKFLOW_PROMPT_TOOL (line 13) | const EXPLAIN_WORKFLOW_PROMPT_TOOL = `Please explain why the following t...
constant EXPLAIN_WORKFLOW_PROMPT_TRANSITION (line 15) | const EXPLAIN_WORKFLOW_PROMPT_TRANSITION = `Please explain why the follo...
FILE: apps/rowboat/app/projects/[projectId]/sources/[sourceId]/page.tsx
function Page (line 4) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/sources/[sourceId]/source-page.tsx
function SourcePage (line 23) | function SourcePage({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/delete.tsx
function DeleteSource (line 6) | function DeleteSource({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/files-source.tsx
function FileListItem (line 13) | function FileListItem({
function PaginatedFileList (line 88) | function PaginatedFileList({
function FilesSource (line 170) | function FilesSource({
function formatFileSize (line 306) | function formatFileSize(bytes: number): string {
FILE: apps/rowboat/app/projects/[projectId]/sources/components/scrape-source.tsx
function UrlListItem (line 15) | function UrlListItem({ file, onDelete }: {
function UrlList (line 54) | function UrlList({ sourceId, onDelete }: {
function ScrapeSource (line 121) | function ScrapeSource({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/section.tsx
type SectionProps (line 3) | interface SectionProps {
function Section (line 10) | function Section({ title, description, children, className }: SectionPro...
function SectionRow (line 30) | function SectionRow({ children, className }: { children: ReactNode; clas...
function SectionLabel (line 38) | function SectionLabel({ children, className }: { children: ReactNode; cl...
function SectionContent (line 46) | function SectionContent({ children, className }: { children: ReactNode; ...
FILE: apps/rowboat/app/projects/[projectId]/sources/components/self-updating-source-status.tsx
function SelfUpdatingSourceStatus (line 8) | function SelfUpdatingSourceStatus({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/shared.tsx
function UrlList (line 1) | function UrlList({ urls }: { urls: string }) {
function TableLabel (line 7) | function TableLabel({ children, className }: { children: React.ReactNode...
function TableValue (line 11) | function TableValue({ children, className }: { children: React.ReactNode...
FILE: apps/rowboat/app/projects/[projectId]/sources/components/source-status.tsx
function SourceStatus (line 6) | function SourceStatus({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/sources-list.tsx
function SourcesList (line 15) | function SourcesList({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/sources/components/text-source.tsx
function TextSource (line 11) | function TextSource({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/toggle-source.tsx
function ToggleSource (line 6) | function ToggleSource({
FILE: apps/rowboat/app/projects/[projectId]/sources/components/web-recrawl.tsx
function Recrawl (line 5) | function Recrawl({
FILE: apps/rowboat/app/projects/[projectId]/sources/new/form.tsx
function Form (line 12) | function Form({
FILE: apps/rowboat/app/projects/[projectId]/sources/new/page.tsx
function Page (line 11) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/sources/page.tsx
function Page (line 9) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/tools/components/AddWebhookTool.tsx
type AddWebhookToolProps (line 9) | interface AddWebhookToolProps {
function AddWebhookTool (line 14) | function AddWebhookTool({ projectId, onAddTool }: AddWebhookToolProps) {
FILE: apps/rowboat/app/projects/[projectId]/tools/components/ComposioToolsPanel.tsx
type ToolType (line 15) | type ToolType = z.infer<typeof ZTool>;
type ToolListResponse (line 16) | type ToolListResponse = z.infer<ReturnType<typeof ZListResponse<typeof Z...
type ComposioToolsPanelProps (line 18) | interface ComposioToolsPanelProps {
function ComposioToolsPanel (line 33) | function ComposioToolsPanel({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/CustomMcpServer.tsx
type CustomMcpServer (line 19) | type CustomMcpServer = z.infer<typeof CustomMcpServerType>;
type ServerList (line 21) | type ServerList = Record<string, CustomMcpServer>;
type CustomMcpServersProps (line 23) | type CustomMcpServersProps = {
function CustomMcpServers (line 28) | function CustomMcpServers({ tools: workflowTools, onAddTool }: CustomMcp...
FILE: apps/rowboat/app/projects/[projectId]/tools/components/MCPServersCommon.tsx
type McpServerType (line 13) | type McpServerType = z.infer<typeof MCPServer>;
type McpToolType (line 14) | type McpToolType = z.infer<typeof McpTool>;
type ServerLogoProps (line 16) | interface ServerLogoProps {
function ServerLogo (line 22) | function ServerLogo({ serverName, className = "", fallback }: ServerLogo...
type ServerOperationBannerProps (line 60) | interface ServerOperationBannerProps {
function ServerOperationBanner (line 65) | function ServerOperationBanner({ serverName, operation }: ServerOperatio...
type ToolCardProps (line 105) | interface ToolCardProps {
function ToolCard (line 115) | function ToolCard({
type ServerCardProps (line 190) | interface ServerCardProps {
function ServerCard (line 204) | function ServerCard({
type ToolManagementPanelProps (line 364) | interface ToolManagementPanelProps {
function ToolManagementPanel (line 376) | function ToolManagementPanel({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/McpToolsPanel.tsx
type McpToolsPanelProps (line 10) | interface McpToolsPanelProps {
function McpToolsPanel (line 24) | function McpToolsPanel({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/SelectComposioToolkit.tsx
type ToolkitType (line 18) | type ToolkitType = z.infer<typeof ZToolkit>;
type ToolkitListResponse (line 19) | type ToolkitListResponse = z.infer<ReturnType<typeof ZListResponse<typeo...
type ProjectType (line 20) | type ProjectType = z.infer<typeof Project>;
type SelectComposioToolkitProps (line 22) | interface SelectComposioToolkitProps {
function SelectComposioToolkit (line 31) | function SelectComposioToolkit({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/ServerCard.tsx
type ServerCardProps (line 14) | type ServerCardProps = {
function ServerCard (line 36) | function ServerCard({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/ToolkitAuthModal.tsx
type ToolkitAuthModalProps (line 14) | interface ToolkitAuthModalProps {
function ToolkitAuthModal (line 22) | function ToolkitAuthModal({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/ToolkitCard.tsx
type ToolkitType (line 12) | type ToolkitType = z.infer<typeof ZToolkit>;
type ToolkitCardProps (line 28) | interface ToolkitCardProps {
function ToolkitCard (line 36) | function ToolkitCard({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/ToolsConfig.tsx
type ToolsConfigProps (line 14) | interface ToolsConfigProps {
type ToolkitType (line 22) | type ToolkitType = z.infer<typeof ZToolkit>;
function ToolsConfig (line 24) | function ToolsConfig({
FILE: apps/rowboat/app/projects/[projectId]/tools/components/WebhookConfig.tsx
function WebhookConfig (line 9) | function WebhookConfig({ projectId }: { projectId: string }) {
FILE: apps/rowboat/app/projects/[projectId]/tools/oauth/callback/page.tsx
function OAuthCallback (line 5) | function OAuthCallback() {
FILE: apps/rowboat/app/projects/[projectId]/workflow/app.tsx
function App (line 19) | function App({
FILE: apps/rowboat/app/projects/[projectId]/workflow/components/ComposioTriggerTypesPanel.tsx
type ComposioTriggerTypesPanelProps (line 12) | interface ComposioTriggerTypesPanelProps {
type TriggerType (line 19) | type TriggerType = z.infer<typeof ComposioTriggerType>;
function ComposioTriggerTypesPanel (line 21) | function ComposioTriggerTypesPanel({
FILE: apps/rowboat/app/projects/[projectId]/workflow/components/DataSourcesModal.tsx
type DataSourcesModalProps (line 12) | interface DataSourcesModalProps {
function DataSourcesModal (line 22) | function DataSourcesModal({
FILE: apps/rowboat/app/projects/[projectId]/workflow/components/ToolsModal.tsx
type ToolsModalProps (line 9) | interface ToolsModalProps {
function ToolsModal (line 18) | function ToolsModal({
FILE: apps/rowboat/app/projects/[projectId]/workflow/components/TopBar.tsx
type TopBarProps (line 12) | interface TopBarProps {
function TopBar (line 64) | function TopBar({
FILE: apps/rowboat/app/projects/[projectId]/workflow/components/TriggerConfigForm.tsx
type TriggerConfigFormProps (line 10) | interface TriggerConfigFormProps {
type JsonSchemaProperty (line 19) | interface JsonSchemaProperty {
type JsonSchema (line 27) | interface JsonSchema {
function TriggerConfigForm (line 34) | function TriggerConfigForm({
FILE: apps/rowboat/app/projects/[projectId]/workflow/config_list.tsx
function List (line 3) | function List({
function ListItem (line 22) | function ListItem({
FILE: apps/rowboat/app/projects/[projectId]/workflow/entity_list.tsx
constant GAP_SIZE (line 32) | const GAP_SIZE = 4;
constant PANEL_RATIOS (line 35) | const PANEL_RATIOS = {
type EntityListProps (line 47) | interface EntityListProps {
type EmptyStateProps (line 93) | interface EmptyStateProps {
type ServerCardProps (line 221) | interface ServerCardProps {
type ComposioToolkit (line 302) | type ComposioToolkit = {
type PipelineCardProps (line 309) | interface PipelineCardProps {
function handleToolSelection (line 659) | function handleToolSelection(name: string) {
function handleSelectDataSource (line 663) | function handleSelectDataSource(id: string) {
function AgentDropdown (line 1350) | function AgentDropdown({
function EntityDropdown (line 1396) | function EntityDropdown({
type ComposioCardProps (line 1424) | interface ComposioCardProps {
type AgentTypeModalProps (line 1842) | interface AgentTypeModalProps {
function AgentTypeModal (line 1849) | function AgentTypeModal({ isOpen, onClose, onConfirm, onCreatePipeline }...
type AddVariableModalProps (line 2026) | interface AddVariableModalProps {
function AddVariableModal (line 2035) | function AddVariableModal({ isOpen, onClose, onConfirm, initialName, ini...
FILE: apps/rowboat/app/projects/[projectId]/workflow/error.tsx
function Error (line 4) | function Error(props: { error: Error }) {
FILE: apps/rowboat/app/projects/[projectId]/workflow/loading.tsx
function Loading (line 4) | function Loading() {
FILE: apps/rowboat/app/projects/[projectId]/workflow/page.tsx
constant DEFAULT_MODEL (line 24) | const DEFAULT_MODEL = process.env.PROVIDER_DEFAULT_MODEL || "gpt-4.1";
function Page (line 30) | async function Page(
FILE: apps/rowboat/app/projects/[projectId]/workflow/preview-modal.tsx
type PreviewModalContextType (line 10) | type PreviewModalContextType = {
function PreviewModalProvider (line 30) | function PreviewModalProvider({ children }: { children: React.ReactNode ...
function PreviewModal (line 83) | function PreviewModal({
FILE: apps/rowboat/app/projects/[projectId]/workflow/trigger-transform.ts
constant COPILOT_TRIGGER_LIMIT (line 5) | const COPILOT_TRIGGER_LIMIT = 100;
constant DEFAULT_TRIGGER_FETCH_LIMIT (line 7) | const DEFAULT_TRIGGER_FETCH_LIMIT = COPILOT_TRIGGER_LIMIT;
type CopilotTrigger (line 9) | type CopilotTrigger = z.infer<typeof TriggerSchemaForCopilot>;
type TransformParams (line 11) | interface TransformParams {
function transformTriggersForCopilot (line 34) | function transformTriggersForCopilot({
FILE: apps/rowboat/app/projects/[projectId]/workflow/workflow_editor.tsx
constant VIEW_MODE_RATIOS (line 51) | const VIEW_MODE_RATIOS = {
constant PANEL_RATIOS (line 81) | const PANEL_RATIOS = {
type StateItem (line 92) | interface StateItem {
type State (line 109) | interface State {
type Action (line 116) | type Action = {
function reducer (line 255) | function reducer(state: State, action: Action): State {
function useEntitySelection (line 957) | function useEntitySelection() {
function WorkflowEditor (line 963) | function WorkflowEditor({
FILE: apps/rowboat/app/projects/app.tsx
function App (line 6) | function App() {
FILE: apps/rowboat/app/projects/components/build-assistant-section.tsx
constant SHOW_PREBUILT_CARDS (line 30) | const SHOW_PREBUILT_CARDS = process.env.NEXT_PUBLIC_SHOW_PREBUILT_CARDS ...
constant ITEMS_PER_PAGE (line 34) | const ITEMS_PER_PAGE = 10;
function BuildAssistantSection (line 55) | function BuildAssistantSection() {
FILE: apps/rowboat/app/projects/components/create-project.tsx
type TabState (line 67) | type TabState = typeof TabType[keyof typeof TabType];
type CreateProjectProps (line 128) | interface CreateProjectProps {
function CreateProject (line 135) | function CreateProject({ defaultName, onOpenProjectPane, isProjectPaneOp...
FILE: apps/rowboat/app/projects/components/custom-prompt-card.tsx
type CustomPromptCardProps (line 7) | interface CustomPromptCardProps {
function CustomPromptCard (line 15) | function CustomPromptCard({
FILE: apps/rowboat/app/projects/components/project-list.tsx
type ProjectListProps (line 11) | interface ProjectListProps {
constant ITEMS_PER_PAGE (line 17) | const ITEMS_PER_PAGE = 10;
function ProjectList (line 19) | function ProjectList({ projects, isLoading, searchQuery }: ProjectListPr...
FILE: apps/rowboat/app/projects/components/search-input.tsx
type TimeFilter (line 6) | type TimeFilter = 'all' | 'today' | 'week' | 'month';
type SearchInputProps (line 8) | interface SearchInputProps {
function SearchInput (line 16) | function SearchInput({
FILE: apps/rowboat/app/projects/components/search-projects.tsx
type SearchProjectsProps (line 8) | interface SearchProjectsProps {
function SearchProjects (line 17) | function SearchProjects({
FILE: apps/rowboat/app/projects/components/submit-button.tsx
function Submit (line 8) | function Submit() {
FILE: apps/rowboat/app/projects/components/templates-section.tsx
type TemplatesSectionProps (line 9) | interface TemplatesSectionProps {}
function TemplatesSection (line 11) | function TemplatesSection({}: TemplatesSectionProps) {
FILE: apps/rowboat/app/projects/layout.tsx
function Layout (line 6) | function Layout({
FILE: apps/rowboat/app/projects/layout/components/app-layout.tsx
type AppLayoutProps (line 9) | interface AppLayoutProps {
function AppLayout (line 15) | function AppLayout({ children, useAuth = false, useBilling = false }: Ap...
FILE: apps/rowboat/app/projects/layout/components/menu-item.tsx
type MenuItemProps (line 3) | interface MenuItemProps {
function MenuItem (line 10) | function MenuItem({
FILE: apps/rowboat/app/projects/layout/components/sidebar.tsx
type SidebarProps (line 34) | interface SidebarProps {
constant EXPANDED_ICON_SIZE (line 42) | const EXPANDED_ICON_SIZE = 20;
constant COLLAPSED_ICON_SIZE (line 43) | const COLLAPSED_ICON_SIZE = 20;
function Sidebar (line 45) | function Sidebar({ projectId, useAuth, collapsed = false, onToggleCollap...
FILE: apps/rowboat/app/projects/layout/index.tsx
function Layout (line 4) | async function Layout({
FILE: apps/rowboat/app/projects/layout/menu.tsx
type NavLinkProps (line 7) | interface NavLinkProps {
function NavLink (line 15) | function NavLink({ href, label, icon, collapsed, selected = false }: Nav...
function Menu (line 29) | function Menu({
FILE: apps/rowboat/app/projects/layout/nav.tsx
function Nav (line 10) | function Nav({
FILE: apps/rowboat/app/projects/lib/project-creation-utils.ts
type CreateProjectOptions (line 5) | interface CreateProjectOptions {
type CreateProjectFromJsonOptions (line 13) | interface CreateProjectFromJsonOptions {
function createProjectWithOptions (line 23) | async function createProjectWithOptions(options: CreateProjectOptions): ...
function createProjectFromJsonWithOptions (line 73) | async function createProjectFromJsonWithOptions(options: CreateProjectFr...
function createProjectFromTemplate (line 112) | async function createProjectFromTemplate(
FILE: apps/rowboat/app/projects/page.tsx
function Page (line 4) | async function Page() {
FILE: apps/rowboat/app/providers.tsx
function Providers (line 7) | function Providers({ className, children }: { className: string, childre...
FILE: apps/rowboat/app/providers/help-modal-provider.tsx
type HelpModalContextType (line 6) | interface HelpModalContextType {
function HelpModalProvider (line 13) | function HelpModalProvider({ children }: { children: ReactNode }) {
function useHelpModal (line 36) | function useHelpModal() {
FILE: apps/rowboat/app/providers/theme-provider.tsx
type Theme (line 5) | type Theme = 'dark' | 'light'
type ThemeProviderProps (line 7) | type ThemeProviderProps = {
type ThemeProviderState (line 12) | type ThemeProviderState = {
function ThemeProvider (line 19) | function ThemeProvider({
function useTheme (line 54) | function useTheme() {
FILE: apps/rowboat/app/scripts/mongodb-drop-indexes.ts
function main (line 5) | async function main() {
FILE: apps/rowboat/app/scripts/mongodb-ensure-indexes.ts
function main (line 5) | async function main() {
FILE: apps/rowboat/app/scripts/rag-worker.ts
constant FILE_PARSING_PROVIDER_API_KEY (line 23) | const FILE_PARSING_PROVIDER_API_KEY = process.env.FILE_PARSING_PROVIDER_...
constant FILE_PARSING_PROVIDER_BASE_URL (line 24) | const FILE_PARSING_PROVIDER_BASE_URL = process.env.FILE_PARSING_PROVIDER...
constant FILE_PARSING_MODEL (line 25) | const FILE_PARSING_MODEL = process.env.FILE_PARSING_MODEL || 'gpt-4.1';
function retryable (line 50) | async function retryable<T>(fn: () => Promise<T>, maxAttempts: number = ...
function runProcessFilePipeline (line 64) | async function runProcessFilePipeline(_logger: PrefixLogger, usageTracke...
function runScrapePipeline (line 179) | async function runScrapePipeline(_logger: PrefixLogger, usageTracker: Us...
function runProcessTextPipeline (line 248) | async function runProcessTextPipeline(_logger: PrefixLogger, usageTracke...
function runDeletionPipeline (line 300) | async function runDeletionPipeline(_logger: PrefixLogger, job: z.infer<t...
FILE: apps/rowboat/app/scripts/setup_qdrant.ts
constant EMBEDDING_VECTOR_SIZE (line 4) | const EMBEDDING_VECTOR_SIZE = Number(process.env.EMBEDDING_VECTOR_SIZE) ...
FILE: apps/rowboat/app/styles/design-tokens.ts
type Tokens (line 107) | type Tokens = typeof tokens;
FILE: apps/rowboat/components/common/AssistantCard.tsx
type AssistantCardProps (line 47) | interface AssistantCardProps {
function AssistantCard (line 76) | function AssistantCard({
FILE: apps/rowboat/components/common/AssistantSection.tsx
type AssistantItem (line 8) | interface AssistantItem {
type AssistantSectionProps (line 25) | interface AssistantSectionProps {
function AssistantSection (line 50) | function AssistantSection({
FILE: apps/rowboat/components/common/UnifiedTemplatesSection.tsx
type TemplateItem (line 11) | interface TemplateItem {
type UnifiedTemplatesSectionProps (line 32) | interface UnifiedTemplatesSectionProps {
function UnifiedTemplatesSection (line 48) | function UnifiedTemplatesSection({
FILE: apps/rowboat/components/common/billing-upgrade-modal.tsx
type BillingUpgradeModalProps (line 10) | interface BillingUpgradeModalProps {
function BillingUpgradeModal (line 16) | function BillingUpgradeModal({ isOpen, onClose, errorMessage }: BillingU...
FILE: apps/rowboat/components/common/compose-box-copilot.tsx
type FlexibleMessage (line 8) | type FlexibleMessage = {
type ComposeBoxCopilotProps (line 17) | interface ComposeBoxCopilotProps {
function ComposeBoxCopilot (line 28) | function ComposeBoxCopilot({
function SendIcon (line 153) | function SendIcon({ size, className }: { size: number, className?: strin...
function StopIcon (line 173) | function StopIcon({ size, className }: { size: number, className?: strin...
function CopilotStatusBar (line 188) | function CopilotStatusBar({
FILE: apps/rowboat/components/common/compose-box-playground.tsx
type ComposeBoxPlaygroundProps (line 5) | interface ComposeBoxPlaygroundProps {
function ComposeBoxPlayground (line 15) | function ComposeBoxPlayground({
function SendIcon (line 133) | function SendIcon({ size, className }: { size: number, className?: strin...
function StopIcon (line 153) | function StopIcon({ size, className }: { size: number, className?: strin...
FILE: apps/rowboat/components/common/compose-box.tsx
type FlexibleMessage (line 8) | type FlexibleMessage = {
function ComposeBox (line 17) | function ComposeBox({
function SendIcon (line 144) | function SendIcon({ size, className }: { size: number, className?: strin...
FILE: apps/rowboat/components/common/copy-as-json-button.tsx
function CopyAsJsonButton (line 3) | function CopyAsJsonButton({ onCopy }: { onCopy: () => void }) {
FILE: apps/rowboat/components/common/copy-button.tsx
function CopyButton (line 6) | function CopyButton({
FILE: apps/rowboat/components/common/help-modal.tsx
type HelpModalProps (line 4) | interface HelpModalProps {
function HelpModal (line 10) | function HelpModal({ isOpen, onClose, onStartTour }: HelpModalProps) {
FILE: apps/rowboat/components/common/panel-common.tsx
function ActionButton (line 7) | function ActionButton({
type PanelProps (line 34) | interface PanelProps {
function Panel (line 50) | function Panel({
FILE: apps/rowboat/components/common/product-tour.tsx
type TourStep (line 6) | interface TourStep {
constant TOUR_STEPS (line 12) | const TOUR_STEPS: TourStep[] = [
function TourBackdrop (line 60) | function TourBackdrop({ targetElement }: { targetElement: Element | null...
function ProductTour (line 138) | function ProductTour({
FILE: apps/rowboat/components/common/project-wide-change-confirmation-modal.tsx
type ProjectWideChangeConfirmationModalProps (line 6) | interface ProjectWideChangeConfirmationModalProps {
function ProjectWideChangeConfirmationModal (line 17) | function ProjectWideChangeConfirmationModal({
FILE: apps/rowboat/components/common/section-card.tsx
type SectionCardProps (line 4) | interface SectionCardProps {
function SectionCard (line 19) | function SectionCard({ icon, title, children, labelWidth = 'md:w-32', cl...
FILE: apps/rowboat/components/common/tool-param-card.tsx
function ToolParamCard (line 10) | function ToolParamCard({
FILE: apps/rowboat/components/ui/button.tsx
type ButtonProps (line 4) | interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
FILE: apps/rowboat/components/ui/dropdown.tsx
type DropdownOption (line 4) | interface DropdownOption {
type DropdownProps (line 11) | interface DropdownProps extends Omit<SelectProps, 'children' | 'onChange...
function Dropdown (line 20) | function Dropdown({
FILE: apps/rowboat/components/ui/horizontal-divider.tsx
type HorizontalDividerProps (line 3) | interface HorizontalDividerProps {
function HorizontalDivider (line 7) | function HorizontalDivider({ className }: HorizontalDividerProps) {
FILE: apps/rowboat/components/ui/input.tsx
type InputProps (line 4) | interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
FILE: apps/rowboat/components/ui/modal.tsx
type ModalProps (line 7) | interface ModalProps {
function Modal (line 14) | function Modal({ isOpen, onClose, title, children }: ModalProps) {
FILE: apps/rowboat/components/ui/page-header.tsx
type PageHeaderProps (line 1) | interface PageHeaderProps {
function PageHeader (line 7) | function PageHeader({ title, description, children }: PageHeaderProps) {
FILE: apps/rowboat/components/ui/page-heading.tsx
type PageHeadingProps (line 4) | interface PageHeadingProps {
function PageHeading (line 9) | function PageHeading({ title, description }: PageHeadingProps) {
FILE: apps/rowboat/components/ui/picture-img.tsx
type SourceProps (line 3) | interface SourceProps {
type PictureImgProps (line 10) | interface PictureImgProps extends React.ImgHTMLAttributes<HTMLImageEleme...
function PictureImg (line 18) | function PictureImg({
FILE: apps/rowboat/components/ui/progress-bar.tsx
type ProgressStep (line 6) | interface ProgressStep {
type ProgressBarProps (line 15) | interface ProgressBarProps {
function ProgressBar (line 21) | function ProgressBar({ steps, className, onStepClick }: ProgressBarProps) {
FILE: apps/rowboat/components/ui/search-bar.tsx
type SearchBarProps (line 7) | interface SearchBarProps extends Omit<InputHTMLAttributes<HTMLInputEleme...
function SearchBar (line 13) | function SearchBar({
FILE: apps/rowboat/components/ui/section-heading.tsx
type SectionHeadingProps (line 4) | interface SectionHeadingProps {
function SectionHeading (line 9) | function SectionHeading({ children, subheading }: SectionHeadingProps) {
FILE: apps/rowboat/components/ui/slide-panel.tsx
type SlidePanelProps (line 8) | interface SlidePanelProps {
function SlidePanel (line 16) | function SlidePanel({
FILE: apps/rowboat/components/ui/switch.tsx
type SwitchProps (line 5) | interface SwitchProps {
FILE: apps/rowboat/components/ui/textarea.tsx
type TextareaProps (line 4) | interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaEleme...
FILE: apps/rowboat/hooks/use-click-away.ts
function useClickAway (line 3) | function useClickAway(
FILE: apps/rowboat/lib/utils.ts
function cn (line 4) | function cn(...inputs: ClassValue[]) {
FILE: apps/rowboat/lib/utils/date.ts
function isToday (line 1) | function isToday(date: Date): boolean {
function isThisWeek (line 8) | function isThisWeek(date: Date): boolean {
function isThisMonth (line 15) | function isThisMonth(date: Date): boolean {
FILE: apps/rowboat/middleware.ts
function authCheck (line 9) | async function authCheck(request: NextRequest) {
function middleware (line 19) | async function middleware(request: NextRequest, event: NextFetchEvent) {
FILE: apps/rowboat/src/application/lib/agents-runtime/agent-handoffs.ts
type HandoffInputData (line 14) | interface HandoffInputData {
type HandoffContextType (line 21) | type HandoffContextType = 'pipeline' | 'task' | 'direct';
type AgentHandoffConfig (line 23) | interface AgentHandoffConfig {
function getDefaultSchemaForContext (line 31) | function getDefaultSchemaForContext(contextType: HandoffContextType): z....
function createDefaultInputFilter (line 44) | function createDefaultInputFilter(contextType: HandoffContextType) {
function filterForPipeline (line 59) | function filterForPipeline(data: HandoffInputData): HandoffInputData {
function filterForTask (line 78) | function filterForTask(data: HandoffInputData): HandoffInputData {
function createAgentHandoff (line 93) | function createAgentHandoff(
function createPipelineHandoff (line 157) | function createPipelineHandoff(
function createTaskHandoff (line 203) | function createTaskHandoff(
function getSchemaForAgent (line 227) | function getSchemaForAgent(agentConfig: z.infer<typeof WorkflowAgent>): ...
function createContextFilterForAgent (line 237) | function createContextFilterForAgent(agentConfig: z.infer<typeof Workflo...
function logHandoffEvent (line 246) | function logHandoffEvent(
function storePipelineStateForAgent (line 262) | function storePipelineStateForAgent(
function getPipelineStateForAgent (line 269) | function getPipelineStateForAgent(
function createPipelineContextMessage (line 275) | function createPipelineContextMessage(context: any): string {
FILE: apps/rowboat/src/application/lib/agents-runtime/agent-tools.ts
constant PROVIDER_API_KEY (line 28) | const PROVIDER_API_KEY = process.env.PROVIDER_API_KEY || process.env.OPE...
constant PROVIDER_BASE_URL (line 29) | const PROVIDER_BASE_URL = process.env.PROVIDER_BASE_URL || undefined;
constant MODEL (line 30) | const MODEL = process.env.PROVIDER_DEFAULT_MODEL || 'gpt-4.1';
constant DEFAULT_IMAGE_MODEL (line 38) | const DEFAULT_IMAGE_MODEL = "gemini-2.5-flash-image-preview";
function invokeGenerateImageTool (line 41) | async function invokeGenerateImageTool(
function invokeMockTool (line 119) | async function invokeMockTool(
function invokeRagTool (line 160) | async function invokeRagTool(
function invokeWebhookTool (line 270) | async function invokeWebhookTool(
function invokeMcpTool (line 350) | async function invokeMcpTool(
function invokeComposioTool (line 388) | async function invokeComposioTool(
function createRagTool (line 434) | function createRagTool(
function createMockTool (line 468) | function createMockTool(
function createWebhookTool (line 507) | function createWebhookTool(
function createMcpTool (line 542) | function createMcpTool(
function createComposioTool (line 577) | function createComposioTool(
function createGenerateImageTool (line 616) | function createGenerateImageTool(
function createTools (line 717) | function createTools(
FILE: apps/rowboat/src/application/lib/agents-runtime/agent_instructions.ts
constant ERROR_ESCALATION_AGENT_INSTRUCTIONS (line 61) | const ERROR_ESCALATION_AGENT_INSTRUCTIONS = `
constant CHILD_TRANSFER_RELATED_INSTRUCTIONS (line 79) | const CHILD_TRANSFER_RELATED_INSTRUCTIONS = `
FILE: apps/rowboat/src/application/lib/agents-runtime/agents.ts
constant PROVIDER_API_KEY (line 23) | const PROVIDER_API_KEY = process.env.PROVIDER_API_KEY || process.env.OPE...
constant PROVIDER_BASE_URL (line 24) | const PROVIDER_BASE_URL = process.env.PROVIDER_BASE_URL || undefined;
constant MODEL (line 25) | const MODEL = process.env.PROVIDER_DEFAULT_MODEL || 'gpt-4.1';
constant USE_NATIVE_HANDOFFS (line 28) | const USE_NATIVE_HANDOFFS = process.env.USE_NATIVE_HANDOFFS === 'true';
constant MAX_AGENT_TURNS (line 31) | const MAX_AGENT_TURNS = 25;
type AgentState (line 75) | interface AgentState {
function createAgent (line 92) | function createAgent(
function convertMsgsInput (line 183) | function convertMsgsInput(messages: z.infer<typeof Message>[]): AgentInp...
function getStartOfTurnAgentName (line 213) | function getStartOfTurnAgentName(
function createTransferEvents (line 287) | function createTransferEvents(
class AgentTransferCounter (line 317) | class AgentTransferCounter {
method increment (line 320) | increment(fromAgent: string, toAgent: string): void {
method get (line 325) | get(fromAgent: string, toAgent: string): number {
function ensureSystemMessage (line 331) | function ensureSystemMessage(logger: PrefixLogger, messages: z.infer<typ...
function mapConfig (line 355) | function mapConfig(workflow: z.infer<typeof Workflow>): {
function createAgentsWithNativeHandoffs (line 406) | function createAgentsWithNativeHandoffs(
function createAgentsLegacy (line 551) | function createAgentsLegacy(
function getGiveUpControlInstructions (line 693) | function getGiveUpControlInstructions(
function maybeInjectGiveUpControlInstructions (line 715) | function maybeInjectGiveUpControlInstructions(
function handlePipelineAgentExecution (line 1187) | function handlePipelineAgentExecution(
function getResponse (line 1550) | async function getResponse(
FILE: apps/rowboat/src/application/lib/agents-runtime/pipeline-state-manager.ts
type PipelineExecutionResult (line 9) | interface PipelineExecutionResult {
class PipelineStateManager (line 19) | class PipelineStateManager {
method constructor (line 23) | constructor(logger: PrefixLogger) {
method initializePipelineExecution (line 28) | initializePipelineExecution(
method handlePipelineExecution (line 59) | async handlePipelineExecution(
method storePipelineState (line 175) | storePipelineState(agentName: string, state: z.infer<typeof PipelineEx...
method getPipelineState (line 181) | getPipelineState(agentName: string): z.infer<typeof PipelineExecutionS...
method clearPipelineState (line 186) | clearPipelineState(agentName: string): void {
method isAgentInPipeline (line 192) | isAgentInPipeline(agentName: string): boolean {
method getActivePipelines (line 197) | getActivePipelines(): Array<{agentName: string, state: z.infer<typeof ...
method injectPipelineContext (line 205) | injectPipelineContext(
method createPipelineContextPrompt (line 224) | private createPipelineContextPrompt(state: z.infer<typeof PipelineExec...
method handlePipelineError (line 268) | handlePipelineError(
method getPipelineStats (line 302) | getPipelineStats(): {
FILE: apps/rowboat/src/application/lib/composio/composio.ts
constant BASE_URL (line 6) | const BASE_URL = 'https://backend.composio.dev/api/v3';
constant COMPOSIO_API_KEY (line 7) | const COMPOSIO_API_KEY = process.env.COMPOSIO_API_KEY || "test";
function composioApiCall (line 18) | async function composioApiCall<T extends z.ZodTypeAny>(
function listToolkits (line 78) | async function listToolkits(cursor: string | null = null): Promise<z.inf...
function getToolkit (line 91) | async function getToolkit(toolkitSlug: string): Promise<z.infer<typeof Z...
function listTools (line 96) | async function listTools(toolkitSlug: string, searchQuery: string | null...
function getTool (line 159) | async function getTool(toolSlug: string): Promise<z.infer<typeof ZTool>> {
function listAuthConfigs (line 215) | async function listAuthConfigs(toolkitSlug: string, cursor: string | nul...
function createAuthConfig (line 229) | async function createAuthConfig(request: z.infer<typeof ZCreateAuthConfi...
function getAuthConfig (line 237) | async function getAuthConfig(authConfigId: string): Promise<z.infer<type...
function deleteAuthConfig (line 242) | async function deleteAuthConfig(authConfigId: string): Promise<z.infer<t...
function createConnectedAccount (line 292) | async function createConnectedAccount(request: z.infer<typeof ZCreateCon...
function getConnectedAccount (line 321) | async function getConnectedAccount(connectedAccountId: string): Promise<...
function deleteConnectedAccount (line 326) | async function deleteConnectedAccount(connectedAccountId: string): Promi...
function listTriggersTypes (line 333) | async function listTriggersTypes(toolkitSlug: string, cursor?: string): ...
function getTriggersType (line 346) | async function getTriggersType(triggerTypeSlug: string): Promise<z.infer...
FILE: apps/rowboat/src/application/lib/copilot/copilot.ts
constant PROVIDER_API_KEY (line 17) | const PROVIDER_API_KEY = process.env.PROVIDER_API_KEY || process.env.OPE...
constant PROVIDER_BASE_URL (line 18) | const PROVIDER_BASE_URL = process.env.PROVIDER_BASE_URL || undefined;
constant COPILOT_MODEL (line 19) | const COPILOT_MODEL = process.env.PROVIDER_COPILOT_MODEL || 'gpt-4.1';
constant AGENT_MODEL (line 20) | const AGENT_MODEL = process.env.PROVIDER_DEFAULT_MODEL || 'gpt-4.1';
constant WORKFLOW_SCHEMA (line 22) | const WORKFLOW_SCHEMA = JSON.stringify(zodToJsonSchema(Workflow));
constant SYSTEM_PROMPT (line 24) | const SYSTEM_PROMPT = [
function getContextPrompt (line 45) | function getContextPrompt(context: z.infer<typeof CopilotChatContext> | ...
function getCurrentWorkflowPrompt (line 68) | function getCurrentWorkflowPrompt(workflow: z.infer<typeof Workflow>): s...
function getDataSourcesPrompt (line 76) | function getDataSourcesPrompt(dataSources: z.infer<typeof DataSourceSche...
function getCurrentTimePrompt (line 95) | function getCurrentTimePrompt(): string {
function getTriggersPrompt (line 99) | function getTriggersPrompt(triggers: z.infer<typeof TriggerSchemaForCopi...
function searchRelevantTools (line 144) | async function searchRelevantTools(usageTracker: UsageTracker, query: st...
function searchRelevantTriggers (line 246) | async function searchRelevantTriggers(
function updateLastUserMessage (line 336) | function updateLastUserMessage(
function getEditAgentInstructionsResponse (line 350) | async function getEditAgentInstructionsResponse(
FILE: apps/rowboat/src/application/lib/copilot/copilot_edit_agent.ts
constant COPILOT_INSTRUCTIONS_EDIT_AGENT (line 1) | const COPILOT_INSTRUCTIONS_EDIT_AGENT = `
FILE: apps/rowboat/src/application/lib/copilot/copilot_multi_agent.ts
function findUsingRowboatDocsDir (line 6) | function findUsingRowboatDocsDir(): string | null {
function stripFrontmatter (line 19) | function stripFrontmatter(content: string): { title: string | null; body...
function sanitizeMdxToPlain (line 35) | function sanitizeMdxToPlain(md: string): string {
function extractOverview (line 52) | function extractOverview(body: string): string {
function collectDocsSummaries (line 64) | function collectDocsSummaries(): string {
constant USING_ROWBOAT_DOCS (line 102) | const USING_ROWBOAT_DOCS = collectDocsSummaries();
constant COPILOT_INSTRUCTIONS_MULTI_AGENT_WITH_DOCS (line 105) | const COPILOT_INSTRUCTIONS_MULTI_AGENT_WITH_DOCS =
FILE: apps/rowboat/src/application/lib/copilot/copilot_multi_agent_build.ts
constant COPILOT_INSTRUCTIONS_MULTI_AGENT (line 1) | const COPILOT_INSTRUCTIONS_MULTI_AGENT = `
FILE: apps/rowboat/src/application/lib/copilot/current_workflow.ts
constant CURRENT_WORKFLOW_PROMPT (line 1) | const CURRENT_WORKFLOW_PROMPT = `
FILE: apps/rowboat/src/application/lib/copilot/example_multi_agent_1.ts
constant COPILOT_MULTI_AGENT_EXAMPLE_1 (line 1) | const COPILOT_MULTI_AGENT_EXAMPLE_1 = `
FILE: apps/rowboat/src/application/lib/utils/is-valid-cron-expression.ts
constant RANGE_SEPARATOR (line 1) | const RANGE_SEPARATOR = "-";
constant STEP_SEPARATOR (line 2) | const STEP_SEPARATOR = "/";
function isValidCronExpression (line 4) | function isValidCronExpression(cron: string): boolean {
FILE: apps/rowboat/src/application/lib/utils/time-to-next-minute.ts
function secondsToNextMinute (line 2) | function secondsToNextMinute(): number {
function minutesToNextHour (line 8) | function minutesToNextHour(): number {
FILE: apps/rowboat/src/application/policies/project-action-authorization.policy.ts
type IProjectActionAuthorizationPolicy (line 13) | interface IProjectActionAuthorizationPolicy {
class ProjectActionAuthorizationPolicy (line 17) | class ProjectActionAuthorizationPolicy implements IProjectActionAuthoriz...
method constructor (line 21) | constructor({
method authorize (line 32) | async authorize(data: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/policies/usage-quota.policy.interface.ts
type IUsageQuotaPolicy (line 3) | interface IUsageQuotaPolicy {
FILE: apps/rowboat/src/application/repositories/api-keys.repository.interface.ts
type IApiKeysRepository (line 11) | interface IApiKeysRepository {
FILE: apps/rowboat/src/application/repositories/composio-trigger-deployments.repository.interface.ts
type IComposioTriggerDeploymentsRepository (line 30) | interface IComposioTriggerDeploymentsRepository {
FILE: apps/rowboat/src/application/repositories/conversations.repository.interface.ts
type IConversationsRepository (line 27) | interface IConversationsRepository {
FILE: apps/rowboat/src/application/repositories/data-source-docs.repository.interface.ts
type IDataSourceDocsRepository (line 34) | interface IDataSourceDocsRepository {
FILE: apps/rowboat/src/application/repositories/data-sources.repository.interface.ts
type IDataSourcesRepository (line 52) | interface IDataSourcesRepository {
FILE: apps/rowboat/src/application/repositories/jobs.repository.interface.ts
type IJobsRepository (line 65) | interface IJobsRepository {
FILE: apps/rowboat/src/application/repositories/project-members.repository.interface.ts
type IProjectMembersRepository (line 10) | interface IProjectMembersRepository {
FILE: apps/rowboat/src/application/repositories/projects.repository.interface.ts
type IProjectsRepository (line 40) | interface IProjectsRepository {
FILE: apps/rowboat/src/application/repositories/recurring-job-rules.repository.interface.ts
type IRecurringJobRulesRepository (line 36) | interface IRecurringJobRulesRepository {
FILE: apps/rowboat/src/application/repositories/scheduled-job-rules.repository.interface.ts
type IScheduledJobRulesRepository (line 45) | interface IScheduledJobRulesRepository {
FILE: apps/rowboat/src/application/repositories/users.repository.interface.ts
type IUsersRepository (line 9) | interface IUsersRepository {
FILE: apps/rowboat/src/application/services/cache.service.interface.ts
type ICacheService (line 8) | interface ICacheService {
FILE: apps/rowboat/src/application/services/pub-sub.service.interface.ts
type Subscription (line 8) | interface Subscription {
type IPubSubService (line 64) | interface IPubSubService {
FILE: apps/rowboat/src/application/services/temp-binary-cache.ts
type Entry (line 3) | type Entry = {
class TempBinaryCache (line 9) | class TempBinaryCache {
method constructor (line 13) | constructor() {
method startCleanup (line 17) | private startCleanup() {
method put (line 28) | put(buf: Buffer, mimeType: string, ttlMs: number = 10 * 60 * 1000): st...
method get (line 35) | get(id: string): { buf: Buffer; mimeType: string } | undefined {
FILE: apps/rowboat/src/application/services/uploads-storage.service.interface.ts
type IUploadsStorageService (line 1) | interface IUploadsStorageService {
FILE: apps/rowboat/src/application/use-cases/api-keys/create-api-key.use-case.ts
class MaxKeysReachedError (line 15) | class MaxKeysReachedError extends BadRequestError {
method constructor (line 16) | constructor(message?: string, options?: ErrorOptions) {
type ICreateApiKeyUseCase (line 21) | interface ICreateApiKeyUseCase {
class CreateApiKeyUseCase (line 25) | class CreateApiKeyUseCase implements ICreateApiKeyUseCase {
method constructor (line 29) | constructor({
method execute (line 40) | async execute(data: z.infer<typeof inputSchema>): Promise<z.infer<type...
FILE: apps/rowboat/src/application/use-cases/api-keys/delete-api-key.use-case.ts
type IDeleteApiKeyUseCase (line 13) | interface IDeleteApiKeyUseCase {
class DeleteApiKeyUseCase (line 17) | class DeleteApiKeyUseCase implements IDeleteApiKeyUseCase {
method constructor (line 21) | constructor({
method execute (line 32) | async execute(data: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/application/use-cases/api-keys/list-api-keys.use-case.ts
type IListApiKeysUseCase (line 13) | interface IListApiKeysUseCase {
class ListApiKeysUseCase (line 17) | class ListApiKeysUseCase implements IListApiKeysUseCase {
method constructor (line 21) | constructor({
method execute (line 32) | async execute(data: z.infer<typeof inputSchema>): Promise<z.infer<type...
FILE: apps/rowboat/src/application/use-cases/composio-trigger-deployments/create-composio-trigger-deployment.use-case.ts
type ICreateComposioTriggerDeploymentUseCase (line 22) | interface ICreateComposioTriggerDeploymentUseCase {
class CreateComposioTriggerDeploymentUseCase (line 26) | class CreateComposioTriggerDeploymentUseCase implements ICreateComposioT...
method constructor (line 32) | constructor({
method execute (line 49) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/composio-trigger-deployments/delete-composio-trigger-deployment.use-case.ts
type IDeleteComposioTriggerDeploymentUseCase (line 17) | interface IDeleteComposioTriggerDeploymentUseCase {
class DeleteComposioTriggerDeploymentUseCase (line 21) | class DeleteComposioTriggerDeploymentUseCase implements IDeleteComposioT...
method constructor (line 27) | constructor({
method execute (line 44) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/application/use-cases/composio-trigger-deployments/fetch-composio-trigger-deployment.use-case.ts
type IFetchComposioTriggerDeploymentUseCase (line 15) | interface IFetchComposioTriggerDeploymentUseCase {
class FetchComposioTriggerDeploymentUseCase (line 19) | class FetchComposioTriggerDeploymentUseCase implements IFetchComposioTri...
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/composio-trigger-deployments/list-composio-trigger-deployments.use-case.ts
type IListComposioTriggerDeploymentsUseCase (line 18) | interface IListComposioTriggerDeploymentsUseCase {
class ListComposioTriggerDeploymentsUseCase (line 22) | class ListComposioTriggerDeploymentsUseCase implements IListComposioTrig...
method constructor (line 27) | constructor({
method execute (line 41) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/composio-trigger-deployments/list-composio-trigger-types.use-case.ts
type IListComposioTriggerTypesUseCase (line 11) | interface IListComposioTriggerTypesUseCase {
class ListComposioTriggerTypesUseCase (line 15) | class ListComposioTriggerTypesUseCase implements IListComposioTriggerTyp...
method execute (line 16) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/composio/webhook/handle-composio-webhook-request.use-case.ts
constant WEBHOOK_SECRET (line 14) | const WEBHOOK_SECRET = process.env.COMPOSIO_TRIGGERS_WEBHOOK_SECRET || "...
type IHandleCompsioWebhookRequestUseCase (line 49) | interface IHandleCompsioWebhookRequestUseCase {
class HandleCompsioWebhookRequestUseCase (line 53) | class HandleCompsioWebhookRequestUseCase implements IHandleCompsioWebhoo...
method constructor (line 60) | constructor({
method execute (line 77) | async execute(request: z.infer<typeof requestSchema>): Promise<void> {
method verifySignature (line 163) | private verifySignature(headers: Record<string, string>, payload: stri...
FILE: apps/rowboat/src/application/use-cases/conversations/create-cached-turn.use-case.ts
type ICreateCachedTurnUseCase (line 18) | interface ICreateCachedTurnUseCase {
class CreateCachedTurnUseCase (line 22) | class CreateCachedTurnUseCase implements ICreateCachedTurnUseCase {
method constructor (line 28) | constructor({
method execute (line 45) | async execute(data: z.infer<typeof inputSchema>): Promise<{ key: strin...
FILE: apps/rowboat/src/application/use-cases/conversations/create-conversation.use-case.ts
type ICreateConversationUseCase (line 21) | interface ICreateConversationUseCase {
class CreateConversationUseCase (line 25) | class CreateConversationUseCase implements ICreateConversationUseCase {
method constructor (line 31) | constructor({
method execute (line 48) | async execute(data: z.infer<typeof inputSchema>): Promise<z.infer<type...
FILE: apps/rowboat/src/application/use-cases/conversations/fetch-cached-turn.use-case.ts
type IFetchCachedTurnUseCase (line 16) | interface IFetchCachedTurnUseCase {
class FetchCachedTurnUseCase (line 20) | class FetchCachedTurnUseCase implements IFetchCachedTurnUseCase {
method constructor (line 26) | constructor({
method execute (line 43) | async execute(data: z.infer<typeof inputSchema>): Promise<z.infer<type...
FILE: apps/rowboat/src/application/use-cases/conversations/fetch-conversation.use-case.ts
type IFetchConversationUseCase (line 15) | interface IFetchConversationUseCase {
class FetchConversationUseCase (line 19) | class FetchConversationUseCase implements IFetchConversationUseCase {
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/conversations/list-conversations.use-case.ts
type IListConversationsUseCase (line 18) | interface IListConversationsUseCase {
class ListConversationsUseCase (line 22) | class ListConversationsUseCase implements IListConversationsUseCase {
method constructor (line 27) | constructor({
method execute (line 41) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/conversations/run-conversation-turn.use-case.ts
type IRunConversationTurnUseCase (line 21) | interface IRunConversationTurnUseCase {
class RunConversationTurnUseCase (line 25) | class RunConversationTurnUseCase implements IRunConversationTurnUseCase {
method constructor (line 30) | constructor({
method execute (line 44) | async *execute(data: z.infer<typeof inputSchema>): AsyncGenerator<z.in...
FILE: apps/rowboat/src/application/use-cases/copilot/create-copilot-cached-turn.use-case.ts
type ICreateCopilotCachedTurnUseCase (line 26) | interface ICreateCopilotCachedTurnUseCase {
class CreateCopilotCachedTurnUseCase (line 30) | class CreateCopilotCachedTurnUseCase implements ICreateCopilotCachedTurn...
method constructor (line 35) | constructor({
method execute (line 49) | async execute(data: z.infer<typeof inputSchema>): Promise<{ key: strin...
FILE: apps/rowboat/src/application/use-cases/copilot/run-copilot-cached-turn.use-case.ts
type IRunCopilotCachedTurnUseCase (line 18) | interface IRunCopilotCachedTurnUseCase {
class RunCopilotCachedTurnUseCase (line 22) | class RunCopilotCachedTurnUseCase implements IRunCopilotCachedTurnUseCase {
method constructor (line 27) | constructor({
method execute (line 41) | async *execute(data: z.infer<typeof inputSchema>): AsyncGenerator<z.in...
FILE: apps/rowboat/src/application/use-cases/data-sources/add-docs-to-data-source.use-case.ts
type IAddDocsToDataSourceUseCase (line 16) | interface IAddDocsToDataSourceUseCase {
class AddDocsToDataSourceUseCase (line 20) | class AddDocsToDataSourceUseCase implements IAddDocsToDataSourceUseCase {
method constructor (line 26) | constructor({
method execute (line 43) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/data-sources/create-data-source.use-case.ts
type ICreateDataSourceUseCase (line 14) | interface ICreateDataSourceUseCase {
class CreateDataSourceUseCase (line 18) | class CreateDataSourceUseCase implements ICreateDataSourceUseCase {
method constructor (line 23) | constructor({
method execute (line 37) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/data-sources/delete-data-source.use-case.ts
type IDeleteDataSourceUseCase (line 14) | interface IDeleteDataSourceUseCase {
class DeleteDataSourceUseCase (line 18) | class DeleteDataSourceUseCase implements IDeleteDataSourceUseCase {
method constructor (line 23) | constructor({
method execute (line 37) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/data-sources/delete-doc-from-data-source.use-case.ts
type IDeleteDocFromDataSourceUseCase (line 15) | interface IDeleteDocFromDataSourceUseCase {
class DeleteDocFromDataSourceUseCase (line 19) | class DeleteDocFromDataSourceUseCase implements IDeleteDocFromDataSource...
method constructor (line 25) | constructor({
method execute (line 42) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/data-sources/fetch-data-source.use-case.ts
type IFetchDataSourceUseCase (line 15) | interface IFetchDataSourceUseCase {
class FetchDataSourceUseCase (line 19) | class FetchDataSourceUseCase implements IFetchDataSourceUseCase {
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/data-sources/get-download-url-for-file.use-case.ts
type IGetDownloadUrlForFileUseCase (line 15) | interface IGetDownloadUrlForFileUseCase {
class GetDownloadUrlForFileUseCase (line 19) | class GetDownloadUrlForFileUseCase implements IGetDownloadUrlForFileUseC...
method constructor (line 26) | constructor({
method execute (line 46) | async execute(request: z.infer<typeof inputSchema>): Promise<string> {
FILE: apps/rowboat/src/application/use-cases/data-sources/get-upload-urls-for-files.use-case.ts
type IGetUploadUrlsForFilesUseCase (line 17) | interface IGetUploadUrlsForFilesUseCase {
class GetUploadUrlsForFilesUseCase (line 21) | class GetUploadUrlsForFilesUseCase implements IGetUploadUrlsForFilesUseC...
method constructor (line 28) | constructor({
method execute (line 48) | async execute(request: z.infer<typeof inputSchema>): Promise<{ fileId:...
FILE: apps/rowboat/src/application/use-cases/data-sources/list-data-sources.use-case.ts
type IListDataSourcesUseCase (line 14) | interface IListDataSourcesUseCase {
class ListDataSourcesUseCase (line 18) | class ListDataSourcesUseCase implements IListDataSourcesUseCase {
method constructor (line 23) | constructor({
method execute (line 37) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/data-sources/list-docs-in-data-source.use-case.ts
type IListDocsInDataSourceUseCase (line 16) | interface IListDocsInDataSourceUseCase {
class ListDocsInDataSourceUseCase (line 20) | class ListDocsInDataSourceUseCase implements IListDocsInDataSourceUseCase {
method constructor (line 26) | constructor({
method execute (line 43) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/data-sources/recrawl-web-data-source.use-case.ts
type IRecrawlWebDataSourceUseCase (line 15) | interface IRecrawlWebDataSourceUseCase {
class RecrawlWebDataSourceUseCase (line 19) | class RecrawlWebDataSourceUseCase implements IRecrawlWebDataSourceUseCase {
method constructor (line 25) | constructor({
method execute (line 42) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/data-sources/toggle-data-source.use-case.ts
type IToggleDataSourceUseCase (line 16) | interface IToggleDataSourceUseCase {
class ToggleDataSourceUseCase (line 20) | class ToggleDataSourceUseCase implements IToggleDataSourceUseCase {
method constructor (line 25) | constructor({
method execute (line 39) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/data-sources/update-data-source.use-case.ts
type IUpdateDataSourceUseCase (line 20) | interface IUpdateDataSourceUseCase {
class UpdateDataSourceUseCase (line 24) | class UpdateDataSourceUseCase implements IUpdateDataSourceUseCase {
method constructor (line 29) | constructor({
method execute (line 43) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/jobs/fetch-job.use-case.ts
type IFetchJobUseCase (line 15) | interface IFetchJobUseCase {
class FetchJobUseCase (line 19) | class FetchJobUseCase implements IFetchJobUseCase {
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/jobs/list-jobs.use-case.ts
type IListJobsUseCase (line 19) | interface IListJobsUseCase {
class ListJobsUseCase (line 23) | class ListJobsUseCase implements IListJobsUseCase {
method constructor (line 28) | constructor({
method execute (line 42) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/projects/add-custom-mcp-server.use-case.ts
type IAddCustomMcpServerUseCase (line 16) | interface IAddCustomMcpServerUseCase {
function validateHttpHttpsUrl (line 20) | function validateHttpHttpsUrl(url: string): string {
class AddCustomMcpServerUseCase (line 28) | class AddCustomMcpServerUseCase implements IAddCustomMcpServerUseCase {
method constructor (line 33) | constructor({
method execute (line 47) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/create-composio-managed-connected-account.use-case.ts
type ICreateComposioManagedConnectedAccountUseCase (line 20) | interface ICreateComposioManagedConnectedAccountUseCase {
class CreateComposioManagedConnectedAccountUseCase (line 24) | class CreateComposioManagedConnectedAccountUseCase implements ICreateCom...
method constructor (line 29) | constructor({
method execute (line 43) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/projects/create-custom-connected-account.use-case.ts
type ICreateCustomConnectedAccountUseCase (line 26) | interface ICreateCustomConnectedAccountUseCase {
class CreateCustomConnectedAccountUseCase (line 30) | class CreateCustomConnectedAccountUseCase implements ICreateCustomConnec...
method constructor (line 35) | constructor({
method execute (line 49) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/projects/create-project.use-case.ts
type ICreateProjectUseCase (line 32) | interface ICreateProjectUseCase {
class CreateProjectUseCase (line 36) | class CreateProjectUseCase implements ICreateProjectUseCase {
method constructor (line 41) | constructor({
method execute (line 55) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/projects/delete-composio-connected-account.use-case.ts
type IDeleteComposioConnectedAccountUseCase (line 19) | interface IDeleteComposioConnectedAccountUseCase {
class DeleteComposioConnectedAccountUseCase (line 23) | class DeleteComposioConnectedAccountUseCase implements IDeleteComposioCo...
method constructor (line 29) | constructor({
method execute (line 46) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/delete-project.use-case.ts
type IDeleteProjectUseCase (line 24) | interface IDeleteProjectUseCase {
class DeleteProjectUseCase (line 28) | class DeleteProjectUseCase implements IDeleteProjectUseCase {
method constructor (line 41) | constructor({ projectsRepository, projectMembersRepository, projectAct...
method execute (line 67) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/fetch-project.use-case.ts
type IFetchProjectUseCase (line 15) | interface IFetchProjectUseCase {
class FetchProjectUseCase (line 19) | class FetchProjectUseCase implements IFetchProjectUseCase {
method constructor (line 25) | constructor({
method execute (line 42) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/projects/get-composio-toolkit.use-case.ts
type IGetComposioToolkitUseCase (line 15) | interface IGetComposioToolkitUseCase {
class GetComposioToolkitUseCase (line 19) | class GetComposioToolkitUseCase implements IGetComposioToolkitUseCase {
method constructor (line 23) | constructor({ projectActionAuthorizationPolicy, usageQuotaPolicy }: { ...
method execute (line 28) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/projects/list-composio-toolkits.use-case.ts
type IListComposioToolkitsUseCase (line 16) | interface IListComposioToolkitsUseCase {
class ListComposioToolkitsUseCase (line 20) | class ListComposioToolkitsUseCase implements IListComposioToolkitsUseCase {
method constructor (line 24) | constructor({ projectActionAuthorizationPolicy, usageQuotaPolicy }: { ...
method execute (line 29) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/projects/list-composio-tools.use-case.ts
type IListComposioToolsUseCase (line 18) | interface IListComposioToolsUseCase {
class ListComposioToolsUseCase (line 22) | class ListComposioToolsUseCase implements IListComposioToolsUseCase {
method constructor (line 26) | constructor({ projectActionAuthorizationPolicy, usageQuotaPolicy }: { ...
method execute (line 31) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/projects/list-projects.use-case.ts
type IListProjectsUseCase (line 12) | interface IListProjectsUseCase {
class ListProjectsUseCase (line 16) | class ListProjectsUseCase implements IListProjectsUseCase {
method constructor (line 19) | constructor({
method execute (line 27) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/projects/remove-custom-mcp-server.use-case.ts
type IRemoveCustomMcpServerUseCase (line 14) | interface IRemoveCustomMcpServerUseCase {
class RemoveCustomMcpServerUseCase (line 18) | class RemoveCustomMcpServerUseCase implements IRemoveCustomMcpServerUseC...
method constructor (line 23) | constructor({
method execute (line 37) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/revert-to-live-workflow.use-case.ts
type IRevertToLiveWorkflowUseCase (line 14) | interface IRevertToLiveWorkflowUseCase {
class RevertToLiveWorkflowUseCase (line 18) | class RevertToLiveWorkflowUseCase implements IRevertToLiveWorkflowUseCase {
method constructor (line 23) | constructor({
method execute (line 37) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/rotate-secret.use-case.ts
type IRotateSecretUseCase (line 14) | interface IRotateSecretUseCase {
class RotateSecretUseCase (line 18) | class RotateSecretUseCase implements IRotateSecretUseCase {
method constructor (line 23) | constructor({ projectsRepository, projectActionAuthorizationPolicy, us...
method execute (line 29) | async execute(request: z.infer<typeof InputSchema>): Promise<string> {
FILE: apps/rowboat/src/application/use-cases/projects/sync-connected-account.use-case.ts
type ISyncConnectedAccountUseCase (line 18) | interface ISyncConnectedAccountUseCase {
class SyncConnectedAccountUseCase (line 22) | class SyncConnectedAccountUseCase implements ISyncConnectedAccountUseCase {
method constructor (line 27) | constructor({
method execute (line 41) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/projects/update-draft-workflow.use-case.ts
type IUpdateDraftWorkflowUseCase (line 15) | interface IUpdateDraftWorkflowUseCase {
class UpdateDraftWorkflowUseCase (line 19) | class UpdateDraftWorkflowUseCase implements IUpdateDraftWorkflowUseCase {
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/update-live-workflow.use-case.ts
type IUpdateLiveWorkflowUseCase (line 15) | interface IUpdateLiveWorkflowUseCase {
class UpdateLiveWorkflowUseCase (line 19) | class UpdateLiveWorkflowUseCase implements IUpdateLiveWorkflowUseCase {
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/update-project-name.use-case.ts
type IUpdateProjectNameUseCase (line 14) | interface IUpdateProjectNameUseCase {
class UpdateProjectNameUseCase (line 18) | class UpdateProjectNameUseCase implements IUpdateProjectNameUseCase {
method constructor (line 23) | constructor({ projectsRepository, projectActionAuthorizationPolicy, us...
method execute (line 29) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/projects/update-webhook-url.use-case.ts
type IUpdateWebhookUrlUseCase (line 14) | interface IUpdateWebhookUrlUseCase {
class UpdateWebhookUrlUseCase (line 18) | class UpdateWebhookUrlUseCase implements IUpdateWebhookUrlUseCase {
method constructor (line 23) | constructor({ projectsRepository, projectActionAuthorizationPolicy, us...
method execute (line 29) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/application/use-cases/recurring-job-rules/create-recurring-job-rule.use-case.ts
type ICreateRecurringJobRuleUseCase (line 21) | interface ICreateRecurringJobRuleUseCase {
class CreateRecurringJobRuleUseCase (line 25) | class CreateRecurringJobRuleUseCase implements ICreateRecurringJobRuleUs...
method constructor (line 30) | constructor({
method execute (line 44) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/recurring-job-rules/delete-recurring-job-rule.use-case.ts
type IDeleteRecurringJobRuleUseCase (line 15) | interface IDeleteRecurringJobRuleUseCase {
class DeleteRecurringJobRuleUseCase (line 19) | class DeleteRecurringJobRuleUseCase implements IDeleteRecurringJobRuleUs...
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/application/use-cases/recurring-job-rules/fetch-recurring-job-rule.use-case.ts
type IFetchRecurringJobRuleUseCase (line 15) | interface IFetchRecurringJobRuleUseCase {
class FetchRecurringJobRuleUseCase (line 19) | class FetchRecurringJobRuleUseCase implements IFetchRecurringJobRuleUseC...
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/recurring-job-rules/list-recurring-job-rules.use-case.ts
type IListRecurringJobRulesUseCase (line 16) | interface IListRecurringJobRulesUseCase {
class ListRecurringJobRulesUseCase (line 20) | class ListRecurringJobRulesUseCase implements IListRecurringJobRulesUseC...
method constructor (line 25) | constructor({
method execute (line 39) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/recurring-job-rules/toggle-recurring-job-rule.use-case.ts
type IToggleRecurringJobRuleUseCase (line 16) | interface IToggleRecurringJobRuleUseCase {
class ToggleRecurringJobRuleUseCase (line 20) | class ToggleRecurringJobRuleUseCase implements IToggleRecurringJobRuleUs...
method constructor (line 25) | constructor({
method execute (line 39) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/recurring-job-rules/update-recurring-job-rule.use-case.ts
type IUpdateRecurringJobRuleUseCase (line 22) | interface IUpdateRecurringJobRuleUseCase {
class UpdateRecurringJobRuleUseCase (line 26) | class UpdateRecurringJobRuleUseCase implements IUpdateRecurringJobRuleUs...
method constructor (line 31) | constructor({
method execute (line 45) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/scheduled-job-rules/create-scheduled-job-rule.use-case.ts
type ICreateScheduledJobRuleUseCase (line 20) | interface ICreateScheduledJobRuleUseCase {
class CreateScheduledJobRuleUseCase (line 24) | class CreateScheduledJobRuleUseCase implements ICreateScheduledJobRuleUs...
method constructor (line 29) | constructor({
method execute (line 43) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/scheduled-job-rules/delete-scheduled-job-rule.use-case.ts
type IDeleteScheduledJobRuleUseCase (line 15) | interface IDeleteScheduledJobRuleUseCase {
class DeleteScheduledJobRuleUseCase (line 19) | class DeleteScheduledJobRuleUseCase implements IDeleteScheduledJobRuleUs...
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/application/use-cases/scheduled-job-rules/fetch-scheduled-job-rule.use-case.ts
type IFetchScheduledJobRuleUseCase (line 15) | interface IFetchScheduledJobRuleUseCase {
class FetchScheduledJobRuleUseCase (line 19) | class FetchScheduledJobRuleUseCase implements IFetchScheduledJobRuleUseC...
method constructor (line 24) | constructor({
method execute (line 38) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/use-cases/scheduled-job-rules/list-scheduled-job-rules.use-case.ts
type IListScheduledJobRulesUseCase (line 16) | interface IListScheduledJobRulesUseCase {
class ListScheduledJobRulesUseCase (line 20) | class ListScheduledJobRulesUseCase implements IListScheduledJobRulesUseC...
method constructor (line 25) | constructor({
method execute (line 39) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/application/use-cases/scheduled-job-rules/update-scheduled-job-rule.use-case.ts
type IUpdateScheduledJobRuleUseCase (line 21) | interface IUpdateScheduledJobRuleUseCase {
class UpdateScheduledJobRuleUseCase (line 25) | class UpdateScheduledJobRuleUseCase implements IUpdateScheduledJobRuleUs...
method constructor (line 30) | constructor({
method execute (line 44) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/application/workers/job-rules.worker.ts
type IJobRulesWorker (line 13) | interface IJobRulesWorker {
class JobRulesWorker (line 18) | class JobRulesWorker implements IJobRulesWorker {
method constructor (line 29) | constructor({
method processScheduledRule (line 51) | private async processScheduledRule(rule: z.infer<typeof ScheduledJobRu...
method processRecurringRule (line 96) | private async processRecurringRule(rule: z.infer<typeof RecurringJobRu...
method pollScheduled (line 133) | private async pollScheduled(): Promise<void> {
method pollRecurring (line 151) | private async pollRecurring(): Promise<void> {
method scheduleNextPoll (line 169) | private scheduleNextPoll(): void {
method run (line 183) | async run(): Promise<void> {
method stop (line 193) | async stop(): Promise<void> {
FILE: apps/rowboat/src/application/workers/jobs.worker.ts
type IJobsWorker (line 14) | interface IJobsWorker {
class JobsWorker (line 19) | class JobsWorker implements IJobsWorker {
method constructor (line 33) | constructor({
method processJob (line 58) | async processJob(job: z.infer<typeof Job>): Promise<void> {
method handleNewJobMessage (line 154) | private async handleNewJobMessage(message: string): Promise<void> {
method pollForJobs (line 186) | private async pollForJobs(): Promise<void> {
method startPolling (line 206) | private async startPolling(): Promise<void> {
method startSubscription (line 222) | private async startSubscription(): Promise<void> {
method run (line 241) | async run(): Promise<void> {
method stop (line 266) | async stop(): Promise<void> {
FILE: apps/rowboat/src/entities/errors/common.ts
class BillingError (line 1) | class BillingError extends Error {
method constructor (line 2) | constructor(message?: string, options?: ErrorOptions) {
class QuotaExceededError (line 7) | class QuotaExceededError extends Error {
method constructor (line 8) | constructor(message?: string, options?: ErrorOptions) {
class BadRequestError (line 13) | class BadRequestError extends Error {
method constructor (line 14) | constructor(message?: string, options?: ErrorOptions) {
class NotFoundError (line 19) | class NotFoundError extends Error {
method constructor (line 20) | constructor(message?: string, options?: ErrorOptions) {
class NotAuthorizedError (line 25) | class NotAuthorizedError extends Error {
method constructor (line 26) | constructor(message?: string, options?: ErrorOptions) {
FILE: apps/rowboat/src/entities/errors/job-errors.ts
class JobAcquisitionError (line 1) | class JobAcquisitionError extends Error {
method constructor (line 2) | constructor(message?: string, options?: ErrorOptions) {
FILE: apps/rowboat/src/entities/models/assistant-template.ts
type AssistantTemplate (line 30) | type AssistantTemplate = z.infer<typeof AssistantTemplate>;
type AssistantTemplateLike (line 40) | type AssistantTemplateLike = z.infer<typeof AssistantTemplateLike>;
FILE: apps/rowboat/src/infrastructure/mongodb/drop-indexes.ts
function dropAllIndexes (line 14) | async function dropAllIndexes(database: Db): Promise<void> {
FILE: apps/rowboat/src/infrastructure/mongodb/ensure-indexes.ts
function ensureAllIndexes (line 16) | async function ensureAllIndexes(database: Db): Promise<void> {
FILE: apps/rowboat/src/infrastructure/policies/redis.usage-quota.policy.ts
constant MAX_QUERIES_PER_MINUTE (line 6) | const MAX_QUERIES_PER_MINUTE = Number(process.env.MAX_QUERIES_PER_MINUTE...
constant MAX_JOBS_PER_HOUR (line 7) | const MAX_JOBS_PER_HOUR = Number(process.env.MAX_JOBS_PER_HOUR) || 0;
class RedisUsageQuotaPolicy (line 9) | class RedisUsageQuotaPolicy implements IUsageQuotaPolicy {
method assertAndConsumeProjectAction (line 10) | async assertAndConsumeProjectAction(projectId: string): Promise<void> {
method assertAndConsumeRunJobAction (line 28) | async assertAndConsumeRunJobAction(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.api-keys.indexes.ts
constant API_KEYS_COLLECTION (line 3) | const API_KEYS_COLLECTION = "api_keys";
constant API_KEYS_INDEXES (line 5) | const API_KEYS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.api-keys.repository.ts
class MongoDBApiKeysRepository (line 13) | class MongoDBApiKeysRepository implements IApiKeysRepository {
method checkAndConsumeKey (line 16) | async checkAndConsumeKey(projectId: string, apiKey: string): Promise<b...
method create (line 24) | async create(data: z.infer<typeof CreateSchema>): Promise<z.infer<type...
method listAll (line 44) | async listAll(projectId: string): Promise<z.infer<typeof ApiKey>[]> {
method delete (line 55) | async delete(projectId: string, id: string): Promise<boolean> {
method deleteAll (line 60) | async deleteAll(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.assistant-templates.repository.ts
class MongoDBAssistantTemplatesRepository (line 10) | class MongoDBAssistantTemplatesRepository {
method create (line 14) | async create(data: Omit<z.infer<typeof AssistantTemplate>, 'id' | 'pub...
method fetch (line 22) | async fetch(id: string): Promise<z.infer<typeof AssistantTemplate> | n...
method list (line 28) | async list(filters: {
method toggleLike (line 63) | async toggleLike(assistantId: string, userId: string, userEmail?: stri...
method getLikeCount (line 77) | async getLikeCount(assistantId: string): Promise<number> {
method getLikedTemplates (line 82) | async getLikedTemplates(templateIds: string[], userId: string): Promis...
method getCategories (line 90) | async getCategories(): Promise<string[]> {
method deleteByIdAndAuthor (line 95) | async deleteByIdAndAuthor(id: string, authorId: string): Promise<boole...
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.community-assistants.indexes.ts
constant COMMUNITY_ASSISTANTS_COLLECTION (line 3) | const COMMUNITY_ASSISTANTS_COLLECTION = "community_assistants";
constant COMMUNITY_ASSISTANT_LIKES_COLLECTION (line 4) | const COMMUNITY_ASSISTANT_LIKES_COLLECTION = "community_assistant_likes";
constant COMMUNITY_ASSISTANTS_INDEXES (line 6) | const COMMUNITY_ASSISTANTS_INDEXES: IndexDescription[] = [
constant COMMUNITY_ASSISTANT_LIKES_INDEXES (line 17) | const COMMUNITY_ASSISTANT_LIKES_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.composio-trigger-deployments.indexes.ts
constant COMPOSIO_TRIGGER_DEPLOYMENTS_COLLECTION (line 3) | const COMPOSIO_TRIGGER_DEPLOYMENTS_COLLECTION = "composio_trigger_deploy...
constant COMPOSIO_TRIGGER_DEPLOYMENTS_INDEXES (line 5) | const COMPOSIO_TRIGGER_DEPLOYMENTS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.composio-trigger-deployments.repository.ts
class MongodbComposioTriggerDeploymentsRepository (line 22) | class MongodbComposioTriggerDeploymentsRepository implements IComposioTr...
method create (line 28) | async create(data: z.infer<typeof CreateDeploymentSchema>): Promise<z....
method fetch (line 52) | async fetch(id: string): Promise<z.infer<typeof ComposioTriggerDeploym...
method fetchByComposioTriggerId (line 70) | async fetchByComposioTriggerId(triggerId: string): Promise<z.infer<typ...
method delete (line 88) | async delete(id: string): Promise<boolean> {
method fetchBySlugAndConnectedAccountId (line 99) | async fetchBySlugAndConnectedAccountId(triggerTypeSlug: string, connec...
method listByProjectId (line 120) | async listByProjectId(projectId: string, cursor?: string, limit: numbe...
method deleteByConnectedAccountId (line 151) | async deleteByConnectedAccountId(connectedAccountId: string): Promise<...
method deleteByProjectId (line 162) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.conversations.indexes.ts
constant CONVERSATIONS_COLLECTION (line 3) | const CONVERSATIONS_COLLECTION = "conversations";
constant CONVERSATIONS_INDEXES (line 5) | const CONVERSATIONS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.conversations.repository.ts
class MongoDBConversationsRepository (line 15) | class MongoDBConversationsRepository implements IConversationsRepository {
method create (line 18) | async create(data: z.infer<typeof CreateConversationData>): Promise<z....
method fetch (line 39) | async fetch(id: string): Promise<z.infer<typeof Conversation> | null> {
method addTurn (line 56) | async addTurn(conversationId: string, data: z.infer<typeof AddTurnData...
method list (line 78) | async list(projectId: string, cursor?: string, limit: number = 50): Pr...
method deleteByProjectId (line 113) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.data-source-docs.indexes.ts
constant DATA_SOURCE_DOCS_COLLECTION (line 3) | const DATA_SOURCE_DOCS_COLLECTION = "source_docs";
constant DATA_SOURCE_DOCS_INDEXES (line 5) | const DATA_SOURCE_DOCS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.data-source-docs.repository.ts
class MongoDBDataSourceDocsRepository (line 23) | class MongoDBDataSourceDocsRepository implements IDataSourceDocsReposito...
method bulkCreate (line 26) | async bulkCreate(projectId: string, sourceId: string, data: z.infer<ty...
method fetch (line 48) | async fetch(id: string): Promise<z.infer<typeof DataSourceDoc> | null> {
method bulkFetch (line 59) | async bulkFetch(ids: string[]): Promise<z.infer<typeof DataSourceDoc>[...
method list (line 67) | async list(
method markSourceDocsPending (line 106) | async markSourceDocsPending(sourceId: string): Promise<void> {
method markAsDeleted (line 119) | async markAsDeleted(id: string): Promise<void> {
method updateByVersion (line 131) | async updateByVersion(
method delete (line 158) | async delete(id: string): Promise<boolean> {
method deleteBySourceId (line 163) | async deleteBySourceId(sourceId: string): Promise<void> {
method deleteByProjectId (line 167) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.data-sources.indexes.ts
constant DATA_SOURCES_COLLECTION (line 3) | const DATA_SOURCES_COLLECTION = "sources";
constant DATA_SOURCES_INDEXES (line 5) | const DATA_SOURCES_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.data-sources.repository.ts
class MongoDBDataSourcesRepository (line 24) | class MongoDBDataSourcesRepository implements IDataSourcesRepository {
method create (line 27) | async create(data: z.infer<typeof CreateSchema>): Promise<z.infer<type...
method fetch (line 54) | async fetch(id: string): Promise<z.infer<typeof DataSource> | null> {
method list (line 65) | async list(
method update (line 109) | async update(
method delete (line 139) | async delete(id: string): Promise<boolean> {
method deleteByProjectId (line 144) | async deleteByProjectId(projectId: string): Promise<void> {
method pollDeleteJob (line 148) | async pollDeleteJob(): Promise<z.infer<typeof DataSource> | null> {
method pollPendingJob (line 162) | async pollPendingJob(): Promise<z.infer<typeof DataSource> | null> {
method release (line 209) | async release(id: string, version: number, updates: z.infer<typeof Rel...
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.jobs.indexes.ts
constant JOBS_COLLECTION (line 3) | const JOBS_COLLECTION = "jobs";
constant JOBS_INDEXES (line 5) | const JOBS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.jobs.repository.ts
class MongoDBJobsRepository (line 24) | class MongoDBJobsRepository implements IJobsRepository {
method create (line 30) | async create(data: z.infer<typeof CreateJobSchema>): Promise<z.infer<t...
method fetch (line 56) | async fetch(id: string): Promise<z.infer<typeof Job> | null> {
method poll (line 74) | async poll(workerId: string): Promise<z.infer<typeof Job> | null> {
method lock (line 112) | async lock(id: string, workerId: string): Promise<z.infer<typeof Job>> {
method update (line 149) | async update(id: string, data: z.infer<typeof UpdateJobSchema>): Promi...
method release (line 182) | async release(id: string): Promise<void> {
method list (line 203) | async list(
method deleteByProjectId (line 271) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.project-members.indexes.ts
constant PROJECT_MEMBERS_COLLECTION (line 3) | const PROJECT_MEMBERS_COLLECTION = "project_members";
constant PROJECT_MEMBERS_INDEXES (line 5) | const PROJECT_MEMBERS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.project-members.repository.ts
class MongoDBProjectMembersRepository (line 12) | class MongoDBProjectMembersRepository implements IProjectMembersReposito...
method create (line 15) | async create(data: z.infer<typeof CreateProjectMemberSchema>): Promise...
method findByUserId (line 47) | async findByUserId(userId: string, cursor?: string, limit: number = 50...
method exists (line 75) | async exists(projectId: string, userId: string): Promise<boolean> {
method deleteByProjectId (line 83) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.projects.indexes.ts
constant PROJECTS_COLLECTION (line 3) | const PROJECTS_COLLECTION = "projects";
constant PROJECTS_INDEXES (line 5) | const PROJECTS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.projects.repository.ts
class MongodbProjectsRepository (line 17) | class MongodbProjectsRepository implements IProjectsRepository {
method constructor (line 21) | constructor({
method create (line 29) | async create(data: z.infer<typeof CreateSchema>): Promise<z.infer<type...
method fetch (line 55) | async fetch(id: string): Promise<z.infer<typeof Project> | null> {
method countCreatedProjects (line 67) | async countCreatedProjects(createdByUserId: string): Promise<number> {
method listProjects (line 71) | async listProjects(userId: string, cursor?: string, limit?: number): P...
method addComposioConnectedAccount (line 86) | async addComposioConnectedAccount(projectId: string, data: z.infer<typ...
method deleteComposioConnectedAccount (line 105) | async deleteComposioConnectedAccount(projectId: string, toolkitSlug: s...
method addCustomMcpServer (line 116) | async addCustomMcpServer(projectId: string, data: z.infer<typeof AddCu...
method deleteCustomMcpServer (line 135) | async deleteCustomMcpServer(projectId: string, name: string): Promise<...
method updateSecret (line 146) | async updateSecret(projectId: string, secret: string): Promise<z.infer...
method updateWebhookUrl (line 164) | async updateWebhookUrl(projectId: string, url: string): Promise<z.infe...
method updateName (line 182) | async updateName(projectId: string, name: string): Promise<z.infer<typ...
method updateDraftWorkflow (line 200) | async updateDraftWorkflow(projectId: string, workflow: z.infer<typeof ...
method updateLiveWorkflow (line 218) | async updateLiveWorkflow(projectId: string, workflow: z.infer<typeof i...
method delete (line 236) | async delete(projectId: string): Promise<boolean> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.recurring-job-rules.indexes.ts
constant RECURRING_JOB_RULES_COLLECTION (line 3) | const RECURRING_JOB_RULES_COLLECTION = "recurring_job_rules";
constant RECURRING_JOB_RULES_INDEXES (line 5) | const RECURRING_JOB_RULES_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.recurring-job-rules.repository.ts
class MongoDBRecurringJobRulesRepository (line 37) | class MongoDBRecurringJobRulesRepository implements IRecurringJobRulesRe...
method convertDocToModel (line 44) | private convertDocToModel(doc: z.infer<typeof DocSchema>): z.infer<typ...
method create (line 57) | async create(data: z.infer<typeof CreateRecurringRuleSchema>): Promise...
method fetch (line 82) | async fetch(id: string): Promise<z.infer<typeof RecurringJobRule> | nu...
method poll (line 96) | async poll(workerId: string): Promise<z.infer<typeof RecurringJobRule>...
method release (line 143) | async release(id: string): Promise<z.infer<typeof RecurringJobRule>> {
method list (line 172) | async list(projectId: string, cursor?: string, limit: number = 50): Pr...
method toggle (line 197) | async toggle(id: string, disabled: boolean): Promise<z.infer<typeof Re...
method update (line 214) | async update(id: string, data: z.infer<typeof UpdateRecurringRuleSchem...
method delete (line 239) | async delete(id: string): Promise<boolean> {
method updateNextRunAt (line 247) | async updateNextRunAt(id: string, cron: string): Promise<z.infer<typeo...
method deleteByProjectId (line 267) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.scheduled-job-rules.indexes.ts
constant SCHEDULED_JOB_RULES_COLLECTION (line 3) | const SCHEDULED_JOB_RULES_COLLECTION = "scheduled_job_rules";
constant SCHEDULED_JOB_RULES_INDEXES (line 5) | const SCHEDULED_JOB_RULES_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.scheduled-job-rules.repository.ts
class MongoDBScheduledJobRulesRepository (line 35) | class MongoDBScheduledJobRulesRepository implements IScheduledJobRulesRe...
method convertDocToModel (line 42) | private convertDocToModel(doc: z.infer<typeof DocSchema>): z.infer<typ...
method create (line 54) | async create(data: z.infer<typeof CreateRuleSchema>): Promise<z.infer<...
method fetch (line 91) | async fetch(id: string): Promise<z.infer<typeof ScheduledJobRule> | nu...
method poll (line 105) | async poll(workerId: string): Promise<z.infer<typeof ScheduledJobRule>...
method updateRule (line 144) | async updateRule(id: string, data: z.infer<typeof UpdateScheduledRuleS...
method update (line 179) | async update(id: string, data: z.infer<typeof UpdateJobSchema>): Promi...
method release (line 196) | async release(id: string): Promise<z.infer<typeof ScheduledJobRule>> {
method list (line 224) | async list(projectId: string, cursor?: string, limit: number = 50): Pr...
method delete (line 249) | async delete(id: string): Promise<boolean> {
method deleteByProjectId (line 257) | async deleteByProjectId(projectId: string): Promise<void> {
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.shared-workflows.indexes.ts
constant SHARED_WORKFLOWS_COLLECTION (line 3) | const SHARED_WORKFLOWS_COLLECTION = "shared_workflows";
constant SHARED_WORKFLOWS_INDEXES (line 5) | const SHARED_WORKFLOWS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.users.indexes.ts
constant USERS_COLLECTION (line 3) | const USERS_COLLECTION = "users";
constant USERS_INDEXES (line 5) | const USERS_INDEXES: IndexDescription[] = [
FILE: apps/rowboat/src/infrastructure/repositories/mongodb.users.repository.ts
class MongoDBUsersRepository (line 12) | class MongoDBUsersRepository implements IUsersRepository {
method create (line 15) | async create(data: z.infer<typeof CreateSchema>): Promise<z.infer<type...
method fetch (line 35) | async fetch(id: string): Promise<z.infer<typeof User> | null> {
method fetchByAuth0Id (line 45) | async fetchByAuth0Id(auth0Id: string): Promise<z.infer<typeof User> | ...
method updateEmail (line 55) | async updateEmail(id: string, email: string): Promise<z.infer<typeof U...
method updateBillingCustomerId (line 69) | async updateBillingCustomerId(id: string, billingCustomerId: string): ...
FILE: apps/rowboat/src/infrastructure/services/local.uploads-storage.service.ts
constant UPLOADS_DIR (line 7) | const UPLOADS_DIR = process.env.RAG_UPLOADS_DIR || '/uploads';
class LocalUploadsStorageService (line 9) | class LocalUploadsStorageService implements IUploadsStorageService {
method constructor (line 12) | constructor({
method getUploadUrl (line 20) | async getUploadUrl(key: string, contentType: string): Promise<string> {
method getDownloadUrl (line 24) | async getDownloadUrl(fileId: string): Promise<string> {
method getFileContents (line 28) | async getFileContents(fileId: string): Promise<Buffer> {
FILE: apps/rowboat/src/infrastructure/services/redis.cache.service.ts
class RedisCacheService (line 4) | class RedisCacheService implements ICacheService {
method get (line 5) | async get(key: string): Promise<string | null> {
method set (line 9) | async set(key: string, value: string, ttl?: number): Promise<void> {
method delete (line 17) | async delete(key: string): Promise<boolean> {
FILE: apps/rowboat/src/infrastructure/services/redis.pub-sub.service.ts
class RedisPubSubService (line 18) | class RedisPubSubService implements IPubSubService {
method constructor (line 22) | constructor() {
method setupRedisSubscriber (line 31) | private setupRedisSubscriber(): void {
method publish (line 60) | async publish(channel: string, message: string): Promise<void> {
method subscribe (line 77) | async subscribe(channel: string, handler: (message: string) => void): ...
method unsubscribe (line 108) | private async unsubscribe(channel: string, handler: (message: string) ...
FILE: apps/rowboat/src/infrastructure/services/s3.uploads-storage.service.ts
class S3UploadsStorageService (line 7) | class S3UploadsStorageService implements IUploadsStorageService {
method constructor (line 12) | constructor({
method getUploadUrl (line 28) | async getUploadUrl(key: string, contentType: string): Promise<string> {
method getDownloadUrl (line 37) | async getDownloadUrl(fileId: string): Promise<string> {
method getFileContents (line 52) | async getFileContents(fileId: string): Promise<Buffer> {
FILE: apps/rowboat/src/interface-adapters/controllers/api-keys/create-api-key.controller.ts
type ICreateApiKeyController (line 13) | interface ICreateApiKeyController {
class CreateApiKeyController (line 17) | class CreateApiKeyController implements ICreateApiKeyController {
method constructor (line 19) | constructor({ createApiKeyUseCase }: { createApiKeyUseCase: ICreateApi...
method execute (line 22) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/api-keys/delete-api-key.controller.ts
type IDeleteApiKeyController (line 13) | interface IDeleteApiKeyController {
class DeleteApiKeyController (line 17) | class DeleteApiKeyController implements IDeleteApiKeyController {
method constructor (line 19) | constructor({ deleteApiKeyUseCase }: { deleteApiKeyUseCase: IDeleteApi...
method execute (line 22) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/interface-adapters/controllers/api-keys/list-api-keys.controller.ts
type IListApiKeysController (line 13) | interface IListApiKeysController {
class ListApiKeysController (line 17) | class ListApiKeysController implements IListApiKeysController {
method constructor (line 19) | constructor({ listApiKeysUseCase }: { listApiKeysUseCase: IListApiKeys...
method execute (line 22) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/composio-trigger-deployments/create-composio-trigger-deployment.controller.ts
type ICreateComposioTriggerDeploymentController (line 18) | interface ICreateComposioTriggerDeploymentController {
class CreateComposioTriggerDeploymentController (line 22) | class CreateComposioTriggerDeploymentController implements ICreateCompos...
method constructor (line 25) | constructor({
method execute (line 33) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/composio-trigger-deployments/delete-composio-trigger-deployment.controller.ts
type IDeleteComposioTriggerDeploymentController (line 13) | interface IDeleteComposioTriggerDeploymentController {
class DeleteComposioTriggerDeploymentController (line 17) | class DeleteComposioTriggerDeploymentController implements IDeleteCompos...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/interface-adapters/controllers/composio-trigger-deployments/fetch-composio-trigger-deployment.controller.ts
type IFetchComposioTriggerDeploymentController (line 13) | interface IFetchComposioTriggerDeploymentController {
class FetchComposioTriggerDeploymentController (line 17) | class FetchComposioTriggerDeploymentController implements IFetchComposio...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/composio-trigger-deployments/list-composio-trigger-deployments.controller.ts
type IListComposioTriggerDeploymentsController (line 16) | interface IListComposioTriggerDeploymentsController {
class ListComposioTriggerDeploymentsController (line 20) | class ListComposioTriggerDeploymentsController implements IListComposioT...
method constructor (line 23) | constructor({
method execute (line 31) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/composio-trigger-deployments/list-composio-trigger-types.controller.ts
type IListComposioTriggerTypesController (line 12) | interface IListComposioTriggerTypesController {
class ListComposioTriggerTypesController (line 16) | class ListComposioTriggerTypesController implements IListComposioTrigger...
method constructor (line 19) | constructor({
method execute (line 27) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/composio/webhook/handle-composio-webhook-request.controller.ts
type IHandleComposioWebhookRequestController (line 10) | interface IHandleComposioWebhookRequestController {
class HandleComposioWebhookRequestController (line 14) | class HandleComposioWebhookRequestController implements IHandleComposioW...
method constructor (line 17) | constructor({
method execute (line 25) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/conversations/create-cached-turn.controller.ts
type ICreateCachedTurnController (line 14) | interface ICreateCachedTurnController {
class CreateCachedTurnController (line 18) | class CreateCachedTurnController implements ICreateCachedTurnController {
method constructor (line 21) | constructor({
method execute (line 29) | async execute(request: z.infer<typeof inputSchema>): Promise<{ key: st...
FILE: apps/rowboat/src/interface-adapters/controllers/conversations/create-playground-conversation.controller.ts
type ICreatePlaygroundConversationController (line 14) | interface ICreatePlaygroundConversationController {
class CreatePlaygroundConversationController (line 18) | class CreatePlaygroundConversationController implements ICreatePlaygroun...
method constructor (line 21) | constructor({
method execute (line 29) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/conversations/fetch-conversation.controller.ts
type IFetchConversationController (line 13) | interface IFetchConversationController {
class FetchConversationController (line 17) | class FetchConversationController implements IFetchConversationController {
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/conversations/list-conversations.controller.ts
type IListConversationsController (line 17) | interface IListConversationsController {
class ListConversationsController (line 21) | class ListConversationsController implements IListConversationsController {
method constructor (line 24) | constructor({
method execute (line 32) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/conversations/run-cached-turn.controller.ts
type IRunCachedTurnController (line 14) | interface IRunCachedTurnController {
class RunCachedTurnController (line 18) | class RunCachedTurnController implements IRunCachedTurnController {
method constructor (line 22) | constructor({
method execute (line 33) | async *execute(request: z.infer<typeof inputSchema>): AsyncGenerator<z...
FILE: apps/rowboat/src/interface-adapters/controllers/conversations/run-turn.controller.ts
type outputSchema (line 17) | type outputSchema = {
type IRunTurnController (line 25) | interface IRunTurnController {
class RunTurnController (line 29) | class RunTurnController implements IRunTurnController {
method constructor (line 33) | constructor({
method execute (line 44) | async execute(request: z.infer<typeof inputSchema>): Promise<outputSch...
FILE: apps/rowboat/src/interface-adapters/controllers/copilot/create-copilot-cached-turn.controller.ts
type ICreateCopilotCachedTurnController (line 21) | interface ICreateCopilotCachedTurnController {
class CreateCopilotCachedTurnController (line 25) | class CreateCopilotCachedTurnController implements ICreateCopilotCachedT...
method constructor (line 28) | constructor({
method execute (line 36) | async execute(request: z.infer<typeof inputSchema>): Promise<{ key: st...
FILE: apps/rowboat/src/interface-adapters/controllers/copilot/run-copilot-cached-turn.controller.ts
type IRunCopilotCachedTurnController (line 13) | interface IRunCopilotCachedTurnController {
class RunCopilotCachedTurnController (line 17) | class RunCopilotCachedTurnController implements IRunCopilotCachedTurnCon...
method constructor (line 20) | constructor({
method execute (line 28) | async *execute(request: z.infer<typeof inputSchema>): AsyncGenerator<z...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/add-docs-to-data-source.controller.ts
type IAddDocsToDataSourceController (line 14) | interface IAddDocsToDataSourceController {
class AddDocsToDataSourceController (line 18) | class AddDocsToDataSourceController implements IAddDocsToDataSourceContr...
method constructor (line 21) | constructor({ addDocsToDataSourceUseCase }: { addDocsToDataSourceUseCa...
method execute (line 25) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/create-data-source.controller.ts
type ICreateDataSourceController (line 14) | interface ICreateDataSourceController {
class CreateDataSourceController (line 18) | class CreateDataSourceController implements ICreateDataSourceController {
method constructor (line 21) | constructor({ createDataSourceUseCase }: { createDataSourceUseCase: IC...
method execute (line 25) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/delete-data-source.controller.ts
type IDeleteDataSourceController (line 12) | interface IDeleteDataSourceController {
class DeleteDataSourceController (line 16) | class DeleteDataSourceController implements IDeleteDataSourceController {
method constructor (line 19) | constructor({ deleteDataSourceUseCase }: { deleteDataSourceUseCase: ID...
method execute (line 23) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/delete-doc-from-data-source.controller.ts
type IDeleteDocFromDataSourceController (line 12) | interface IDeleteDocFromDataSourceController {
class DeleteDocFromDataSourceController (line 16) | class DeleteDocFromDataSourceController implements IDeleteDocFromDataSou...
method constructor (line 19) | constructor({ deleteDocFromDataSourceUseCase }: { deleteDocFromDataSou...
method execute (line 23) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/fetch-data-source.controller.ts
type IFetchDataSourceController (line 13) | interface IFetchDataSourceController {
class FetchDataSourceController (line 17) | class FetchDataSourceController implements IFetchDataSourceController {
method constructor (line 20) | constructor({ fetchDataSourceUseCase }: { fetchDataSourceUseCase: IFet...
method execute (line 24) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/get-download-url-for-file.controller.ts
type IGetDownloadUrlForFileController (line 12) | interface IGetDownloadUrlForFileController {
class GetDownloadUrlForFileController (line 16) | class GetDownloadUrlForFileController implements IGetDownloadUrlForFileC...
method constructor (line 19) | constructor({ getDownloadUrlForFileUseCase }: { getDownloadUrlForFileU...
method execute (line 23) | async execute(request: z.infer<typeof inputSchema>): Promise<string> {
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/get-upload-urls-for-files.controller.ts
type IGetUploadUrlsForFilesController (line 13) | interface IGetUploadUrlsForFilesController {
class GetUploadUrlsForFilesController (line 17) | class GetUploadUrlsForFilesController implements IGetUploadUrlsForFilesC...
method constructor (line 20) | constructor({ getUploadUrlsForFilesUseCase }: { getUploadUrlsForFilesU...
method execute (line 24) | async execute(request: z.infer<typeof inputSchema>): Promise<{ fileId:...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/list-data-sources.controller.ts
type IListDataSourcesController (line 13) | interface IListDataSourcesController {
class ListDataSourcesController (line 17) | class ListDataSourcesController implements IListDataSourcesController {
method constructor (line 20) | constructor({ listDataSourcesUseCase }: { listDataSourcesUseCase: ILis...
method execute (line 24) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/list-docs-in-data-source.controller.ts
type IListDocsInDataSourceController (line 13) | interface IListDocsInDataSourceController {
class ListDocsInDataSourceController (line 17) | class ListDocsInDataSourceController implements IListDocsInDataSourceCon...
method constructor (line 20) | constructor({ listDocsInDataSourceUseCase }: { listDocsInDataSourceUse...
method execute (line 24) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/recrawl-web-data-source.controller.ts
type IRecrawlWebDataSourceController (line 12) | interface IRecrawlWebDataSourceController {
class RecrawlWebDataSourceController (line 16) | class RecrawlWebDataSourceController implements IRecrawlWebDataSourceCon...
method constructor (line 19) | constructor({ recrawlWebDataSourceUseCase }: { recrawlWebDataSourceUse...
method execute (line 23) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/toggle-data-source.controller.ts
type IToggleDataSourceController (line 14) | interface IToggleDataSourceController {
class ToggleDataSourceController (line 18) | class ToggleDataSourceController implements IToggleDataSourceController {
method constructor (line 21) | constructor({ toggleDataSourceUseCase }: { toggleDataSourceUseCase: IT...
method execute (line 25) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/data-sources/update-data-source.controller.ts
type IUpdateDataSourceController (line 18) | interface IUpdateDataSourceController {
class UpdateDataSourceController (line 22) | class UpdateDataSourceController implements IUpdateDataSourceController {
method constructor (line 25) | constructor({ updateDataSourceUseCase }: { updateDataSourceUseCase: IU...
method execute (line 29) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/jobs/fetch-job.controller.ts
type IFetchJobController (line 13) | interface IFetchJobController {
class FetchJobController (line 17) | class FetchJobController implements IFetchJobController {
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/jobs/list-jobs.controller.ts
type IListJobsController (line 18) | interface IListJobsController {
class ListJobsController (line 22) | class ListJobsController implements IListJobsController {
method constructor (line 25) | constructor({
method execute (line 33) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/add-custom-mcp-server.controller.ts
type IAddCustomMcpServerController (line 15) | interface IAddCustomMcpServerController {
class AddCustomMcpServerController (line 19) | class AddCustomMcpServerController implements IAddCustomMcpServerControl...
method constructor (line 22) | constructor({ addCustomMcpServerUseCase }: { addCustomMcpServerUseCase...
method execute (line 26) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/create-composio-managed-connected-account.controller.ts
type ICreateComposioManagedConnectedAccountController (line 15) | interface ICreateComposioManagedConnectedAccountController {
class CreateComposioManagedConnectedAccountController (line 19) | class CreateComposioManagedConnectedAccountController implements ICreate...
method constructor (line 22) | constructor({ createComposioManagedConnectedAccountUseCase }: { create...
method execute (line 26) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/create-custom-connected-account.controller.ts
type ICreateCustomConnectedAccountController (line 21) | interface ICreateCustomConnectedAccountController {
class CreateCustomConnectedAccountController (line 25) | class CreateCustomConnectedAccountController implements ICreateCustomCon...
method constructor (line 28) | constructor({ createCustomConnectedAccountUseCase }: { createCustomCon...
method execute (line 32) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/create-project.controller.ts
type ICreateProjectController (line 6) | interface ICreateProjectController {
class CreateProjectController (line 10) | class CreateProjectController implements ICreateProjectController {
method constructor (line 13) | constructor({
method execute (line 21) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/delete-composio-connected-account.controller.ts
type IDeleteComposioConnectedAccountController (line 13) | interface IDeleteComposioConnectedAccountController {
class DeleteComposioConnectedAccountController (line 17) | class DeleteComposioConnectedAccountController implements IDeleteComposi...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/delete-project.controller.ts
type IDeleteProjectController (line 6) | interface IDeleteProjectController {
class DeleteProjectController (line 10) | class DeleteProjectController implements IDeleteProjectController {
method constructor (line 13) | constructor({
method execute (line 21) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/fetch-project.controller.ts
type IFetchProjectController (line 13) | interface IFetchProjectController {
class FetchProjectController (line 17) | class FetchProjectController implements IFetchProjectController {
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/get-composio-toolkit.controller.ts
type IGetComposioToolkitController (line 14) | interface IGetComposioToolkitController {
class GetComposioToolkitController (line 18) | class GetComposioToolkitController implements IGetComposioToolkitControl...
method constructor (line 21) | constructor({ getComposioToolkitUseCase }: { getComposioToolkitUseCase...
method execute (line 25) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/list-composio-toolkits.controller.ts
type IListComposioToolkitsController (line 15) | interface IListComposioToolkitsController {
class ListComposioToolkitsController (line 19) | class ListComposioToolkitsController implements IListComposioToolkitsCon...
method constructor (line 22) | constructor({ listComposioToolkitsUseCase }: { listComposioToolkitsUse...
method execute (line 26) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/list-composio-tools.controller.ts
type IListComposioToolsController (line 17) | interface IListComposioToolsController {
class ListComposioToolsController (line 21) | class ListComposioToolsController implements IListComposioToolsController {
method constructor (line 24) | constructor({ listComposioToolsUseCase }: { listComposioToolsUseCase: ...
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/list-projects.controller.ts
type IListProjectsController (line 8) | interface IListProjectsController {
class ListProjectsController (line 12) | class ListProjectsController implements IListProjectsController {
method constructor (line 15) | constructor({
method execute (line 23) | async execute(request: z.infer<typeof InputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/remove-custom-mcp-server.controller.ts
type IRemoveCustomMcpServerController (line 13) | interface IRemoveCustomMcpServerController {
class RemoveCustomMcpServerController (line 17) | class RemoveCustomMcpServerController implements IRemoveCustomMcpServerC...
method constructor (line 20) | constructor({ removeCustomMcpServerUseCase }: { removeCustomMcpServerU...
method execute (line 24) | async execute(request: z.infer<typeof inputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/revert-to-live-workflow.controller.ts
type IRevertToLiveWorkflowController (line 6) | interface IRevertToLiveWorkflowController {
class RevertToLiveWorkflowController (line 10) | class RevertToLiveWorkflowController implements IRevertToLiveWorkflowCon...
method constructor (line 13) | constructor({ revertToLiveWorkflowUseCase }: { revertToLiveWorkflowUse...
method execute (line 17) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/rotate-secret.controller.ts
type IRotateSecretController (line 12) | interface IRotateSecretController {
class RotateSecretController (line 16) | class RotateSecretController implements IRotateSecretController {
method constructor (line 19) | constructor({
method execute (line 27) | async execute(request: z.infer<typeof inputSchema>): Promise<string> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/sync-connected-account.controller.ts
type ISyncConnectedAccountController (line 15) | interface ISyncConnectedAccountController {
class SyncConnectedAccountController (line 19) | class SyncConnectedAccountController implements ISyncConnectedAccountCon...
method constructor (line 22) | constructor({ syncConnectedAccountUseCase }: { syncConnectedAccountUse...
method execute (line 26) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/projects/update-draft-workflow.controller.ts
type IUpdateDraftWorkflowController (line 6) | interface IUpdateDraftWorkflowController {
class UpdateDraftWorkflowController (line 10) | class UpdateDraftWorkflowController implements IUpdateDraftWorkflowContr...
method constructor (line 13) | constructor({ updateDraftWorkflowUseCase }: { updateDraftWorkflowUseCa...
method execute (line 17) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/update-live-workflow.controller.ts
type IUpdateLiveWorkflowController (line 6) | interface IUpdateLiveWorkflowController {
class UpdateLiveWorkflowController (line 10) | class UpdateLiveWorkflowController implements IUpdateLiveWorkflowControl...
method constructor (line 13) | constructor({ updateLiveWorkflowUseCase }: { updateLiveWorkflowUseCase...
method execute (line 17) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/update-project-name.controller.ts
type IUpdateProjectNameController (line 6) | interface IUpdateProjectNameController {
class UpdateProjectNameController (line 10) | class UpdateProjectNameController implements IUpdateProjectNameController {
method constructor (line 13) | constructor({
method execute (line 21) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/projects/update-webhook-url.controller.ts
type IUpdateWebhookUrlController (line 6) | interface IUpdateWebhookUrlController {
class UpdateWebhookUrlController (line 10) | class UpdateWebhookUrlController implements IUpdateWebhookUrlController {
method constructor (line 13) | constructor({
method execute (line 21) | async execute(request: z.infer<typeof InputSchema>): Promise<void> {
FILE: apps/rowboat/src/interface-adapters/controllers/recurring-job-rules/create-recurring-job-rule.controller.ts
type ICreateRecurringJobRuleController (line 17) | interface ICreateRecurringJobRuleController {
class CreateRecurringJobRuleController (line 21) | class CreateRecurringJobRuleController implements ICreateRecurringJobRul...
method constructor (line 24) | constructor({
method execute (line 32) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/recurring-job-rules/delete-recurring-job-rule.controller.ts
type IDeleteRecurringJobRuleController (line 13) | interface IDeleteRecurringJobRuleController {
class DeleteRecurringJobRuleController (line 17) | class DeleteRecurringJobRuleController implements IDeleteRecurringJobRul...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/interface-adapters/controllers/recurring-job-rules/fetch-recurring-job-rule.controller.ts
type IFetchRecurringJobRuleController (line 13) | interface IFetchRecurringJobRuleController {
class FetchRecurringJobRuleController (line 17) | class FetchRecurringJobRuleController implements IFetchRecurringJobRuleC...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/recurring-job-rules/list-recurring-job-rules.controller.ts
type IListRecurringJobRulesController (line 16) | interface IListRecurringJobRulesController {
class ListRecurringJobRulesController (line 20) | class ListRecurringJobRulesController implements IListRecurringJobRulesC...
method constructor (line 23) | constructor({
method execute (line 31) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/recurring-job-rules/toggle-recurring-job-rule.controller.ts
type IToggleRecurringJobRuleController (line 14) | interface IToggleRecurringJobRuleController {
class ToggleRecurringJobRuleController (line 18) | class ToggleRecurringJobRuleController implements IToggleRecurringJobRul...
method constructor (line 21) | constructor({
method execute (line 29) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/recurring-job-rules/update-recurring-job-rule.controller.ts
type IUpdateRecurringJobRuleController (line 18) | interface IUpdateRecurringJobRuleController {
class UpdateRecurringJobRuleController (line 22) | class UpdateRecurringJobRuleController implements IUpdateRecurringJobRul...
method constructor (line 25) | constructor({
method execute (line 33) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/scheduled-job-rules/create-scheduled-job-rule.controller.ts
type ICreateScheduledJobRuleController (line 18) | interface ICreateScheduledJobRuleController {
class CreateScheduledJobRuleController (line 22) | class CreateScheduledJobRuleController implements ICreateScheduledJobRul...
method constructor (line 25) | constructor({
method execute (line 33) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/scheduled-job-rules/delete-scheduled-job-rule.controller.ts
type IDeleteScheduledJobRuleController (line 13) | interface IDeleteScheduledJobRuleController {
class DeleteScheduledJobRuleController (line 17) | class DeleteScheduledJobRuleController implements IDeleteScheduledJobRul...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<boolean> {
FILE: apps/rowboat/src/interface-adapters/controllers/scheduled-job-rules/fetch-scheduled-job-rule.controller.ts
type IFetchScheduledJobRuleController (line 13) | interface IFetchScheduledJobRuleController {
class FetchScheduledJobRuleController (line 17) | class FetchScheduledJobRuleController implements IFetchScheduledJobRuleC...
method constructor (line 20) | constructor({
method execute (line 28) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboat/src/interface-adapters/controllers/scheduled-job-rules/list-scheduled-job-rules.controller.ts
type IListScheduledJobRulesController (line 17) | interface IListScheduledJobRulesController {
class ListScheduledJobRulesController (line 21) | class ListScheduledJobRulesController implements IListScheduledJobRulesC...
method constructor (line 24) | constructor({
method execute (line 32) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<R...
FILE: apps/rowboat/src/interface-adapters/controllers/scheduled-job-rules/update-scheduled-job-rule.controller.ts
type IUpdateScheduledJobRuleController (line 19) | interface IUpdateScheduledJobRuleController {
class UpdateScheduledJobRuleController (line 23) | class UpdateScheduledJobRuleController implements IUpdateScheduledJobRul...
method constructor (line 26) | constructor({
method execute (line 34) | async execute(request: z.infer<typeof inputSchema>): Promise<z.infer<t...
FILE: apps/rowboatx/app/layout.tsx
function RootLayout (line 9) | function RootLayout({
FILE: apps/rowboatx/app/page.tsx
type ChatMessage (line 63) | interface ChatMessage {
type ToolCall (line 71) | interface ToolCall {
type ReasoningBlock (line 81) | interface ReasoningBlock {
type ConversationItem (line 89) | type ConversationItem = ChatMessage | ToolCall | ReasoningBlock;
type ResourceKind (line 91) | type ResourceKind = "agent" | "config" | "run";
type SelectedResource (line 93) | type SelectedResource = {
type ToolCallContentPart (line 98) | type ToolCallContentPart = {
type RunEvent (line 105) | type RunEvent = {
function PageBody (line 110) | function PageBody() {
function HomePage (line 1039) | function HomePage() {
FILE: apps/rowboatx/components/ai-elements/artifact.tsx
type ArtifactProps (line 14) | type ArtifactProps = HTMLAttributes<HTMLDivElement>;
type ArtifactHeaderProps (line 26) | type ArtifactHeaderProps = HTMLAttributes<HTMLDivElement>;
type ArtifactCloseProps (line 41) | type ArtifactCloseProps = ComponentProps<typeof Button>;
type ArtifactTitleProps (line 65) | type ArtifactTitleProps = HTMLAttributes<HTMLParagraphElement>;
type ArtifactDescriptionProps (line 74) | type ArtifactDescriptionProps = HTMLAttributes<HTMLParagraphElement>;
type ArtifactActionsProps (line 83) | type ArtifactActionsProps = HTMLAttributes<HTMLDivElement>;
type ArtifactActionProps (line 92) | type ArtifactActionProps = ComponentProps<typeof Button> & {
type ArtifactContentProps (line 140) | type ArtifactContentProps = HTMLAttributes<HTMLDivElement>;
FILE: apps/rowboatx/components/ai-elements/canvas.tsx
type CanvasProps (line 5) | type CanvasProps = ReactFlowProps & {
FILE: apps/rowboatx/components/ai-elements/chain-of-thought.tsx
type ChainOfThoughtContextValue (line 20) | type ChainOfThoughtContextValue = {
type ChainOfThoughtProps (line 39) | type ChainOfThoughtProps = ComponentProps<"div"> & {
type ChainOfThoughtHeaderProps (line 78) | type ChainOfThoughtHeaderProps = ComponentProps<
type ChainOfThoughtStepProps (line 111) | type ChainOfThoughtStepProps = ComponentProps<"div"> & {
type ChainOfThoughtSearchResultsProps (line 160) | type ChainOfThoughtSearchResultsProps = ComponentProps<"div">;
type ChainOfThoughtSearchResultProps (line 171) | type ChainOfThoughtSearchResultProps = ComponentProps<typeof Badge>;
type ChainOfThoughtContentProps (line 185) | type ChainOfThoughtContentProps = ComponentProps<
type ChainOfThoughtImageProps (line 210) | type ChainOfThoughtImageProps = ComponentProps<"div"> & {
FILE: apps/rowboatx/components/ai-elements/checkpoint.tsx
type CheckpointProps (line 14) | type CheckpointProps = HTMLAttributes<HTMLDivElement>;
type CheckpointIconProps (line 30) | type CheckpointIconProps = LucideProps;
type CheckpointTriggerProps (line 41) | type CheckpointTriggerProps = ComponentProps<typeof Button> & {
FILE: apps/rowboatx/components/ai-elements/code-block.tsx
type CodeBlockProps (line 17) | type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
type CodeBlockContextType (line 23) | type CodeBlockContextType = {
method line (line 33) | line(node, line) {
function highlightCode (line 52) | async function highlightCode(
type CodeBlockCopyButtonProps (line 132) | type CodeBlockCopyButtonProps = ComponentProps<typeof Button> & {
FILE: apps/rowboatx/components/ai-elements/confirmation.tsx
type ToolUIPartApproval (line 14) | type ToolUIPartApproval =
type ConfirmationContextValue (line 42) | type ConfirmationContextValue = {
type ConfirmationProps (line 61) | type ConfirmationProps = ComponentProps<typeof Alert> & {
type ConfirmationTitleProps (line 83) | type ConfirmationTitleProps = ComponentProps<typeof AlertDescription>;
type ConfirmationRequestProps (line 92) | type ConfirmationRequestProps = {
type ConfirmationAcceptedProps (line 108) | type ConfirmationAcceptedProps = {
type ConfirmationRejectedProps (line 132) | type ConfirmationRejectedProps = {
type ConfirmationActionsProps (line 156) | type ConfirmationActionsProps = ComponentProps<"div">;
type ConfirmationActionProps (line 178) | type ConfirmationActionProps = ComponentProps<typeof Button>;
FILE: apps/rowboatx/components/ai-elements/connection.tsx
constant HALF (line 3) | const HALF = 0.5;
FILE: apps/rowboatx/components/ai-elements/context.tsx
constant PERCENT_MAX (line 15) | const PERCENT_MAX = 100;
constant ICON_RADIUS (line 16) | const ICON_RADIUS = 10;
constant ICON_VIEWBOX (line 17) | const ICON_VIEWBOX = 24;
constant ICON_CENTER (line 18) | const ICON_CENTER = 12;
constant ICON_STROKE_WIDTH (line 19) | const ICON_STROKE_WIDTH = 2;
type ModelId (line 21) | type ModelId = string;
type ContextSchema (line 23) | type ContextSchema = {
type ContextProps (line 42) | type ContextProps = ComponentProps<typeof HoverCard> & ContextSchema;
type ContextTriggerProps (line 104) | type ContextTriggerProps = ComponentProps<typeof Button>;
type ContextContentProps (line 128) | type ContextContentProps = ComponentProps<typeof HoverCardContent>;
type ContextContentHeaderProps (line 140) | type ContextContentHeaderProps = ComponentProps<"div">;
type ContextContentBodyProps (line 179) | type ContextContentBodyProps = Compo
Condensed preview — 893 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,083K chars).
[
{
"path": ".gitattributes",
"chars": 0,
"preview": ""
},
{
"path": ".github/workflows/electron-build.yml",
"chars": 8518,
"preview": "name: Build Electron App\n\non:\n release:\n types: [published]\n\npermissions:\n contents: write # Required to upload re"
},
{
"path": ".github/workflows/rowboat-build.yml",
"chars": 1063,
"preview": "name: Rowboat Build\n\non:\n pull_request:\n\njobs:\n build-rowboat-nextjs:\n runs-on: ubuntu-latest\n \n steps:\n "
},
{
"path": ".github/workflows/x-publish.yml",
"chars": 859,
"preview": "name: Publish to npm\n\non: workflow_dispatch\n\npermissions:\n id-token: write # Required for OIDC\n contents: read\n\njobs:"
},
{
"path": ".gitignore",
"chars": 37,
"preview": ".DS_Store\n.env\n.vscode/\ndata/\n.venv/\n"
},
{
"path": "CLAUDE.md",
"chars": 4860,
"preview": "# CLAUDE.md - AI Coding Agent Context\n\nThis file provides context for AI coding agents working on the Rowboat monorepo.\n"
},
{
"path": "Dockerfile.qdrant",
"chars": 104,
"preview": "FROM qdrant/qdrant:latest\n\nRUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* "
},
{
"path": "LICENSE",
"chars": 11346,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 6238,
"preview": "<a href=\"https://www.youtube.com/watch?v=5AWoGo-L16I\" target=\"_blank\" rel=\"noopener noreferrer\">\n <img width=\"1339\" hei"
},
{
"path": "apps/cli/.gitignore",
"chars": 28,
"preview": "node_modules/\ndist/\n.vercel\n"
},
{
"path": "apps/cli/bin/app.js",
"chars": 4139,
"preview": "#!/usr/bin/env node\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { app, modelConfig, impor"
},
{
"path": "apps/cli/package.json",
"chars": 1570,
"preview": "{\n \"name\": \"@rowboatlabs/rowboatx\",\n \"version\": \"0.16.0\",\n \"main\": \"index.js\",\n \"type\": \"module\",\n \"scripts\": {\n "
},
{
"path": "apps/cli/src/agents/agents.ts",
"chars": 784,
"preview": "import { z } from \"zod\";\n\nexport const BaseTool = z.object({\n name: z.string(),\n});\n\nexport const BuiltinTool = BaseT"
},
{
"path": "apps/cli/src/agents/repo.ts",
"chars": 3387,
"preview": "import { WorkDir } from \"../config/config.js\";\nimport fs from \"fs/promises\";\nimport { glob } from \"node:fs/promises\";\nim"
},
{
"path": "apps/cli/src/agents/runtime.ts",
"chars": 30284,
"preview": "import { jsonSchema, ModelMessage, modelMessageSchema } from \"ai\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport "
},
{
"path": "apps/cli/src/app.ts",
"chars": 22407,
"preview": "import { AgentState, streamAgent } from \"./agents/runtime.js\";\nimport { StreamRenderer } from \"./application/lib/stream-"
},
{
"path": "apps/cli/src/application/assistant/agent.ts",
"chars": 556,
"preview": "import { Agent, ToolAttachment } from \"../../agents/agents.js\";\nimport z from \"zod\";\nimport { CopilotInstructions } from"
},
{
"path": "apps/cli/src/application/assistant/instructions.ts",
"chars": 4827,
"preview": "import { skillCatalog } from \"./skills/index.js\";\nimport { WorkDir as BASE_DIR } from \"../../config/config.js\";\nimport {"
},
{
"path": "apps/cli/src/application/assistant/runtime-context.ts",
"chars": 2377,
"preview": "export type RuntimeShellDialect = 'windows-cmd' | 'posix-sh';\nexport type RuntimeOsName = 'Windows' | 'macOS' | 'Linux' "
},
{
"path": "apps/cli/src/application/assistant/skills/builtin-tools/skill.ts",
"chars": 8893,
"preview": "export const skill = String.raw`\n# Builtin Tools Reference\n\nLoad this skill when creating or modifying agents that need "
},
{
"path": "apps/cli/src/application/assistant/skills/deletion-guardrails/skill.ts",
"chars": 1033,
"preview": "export const skill = String.raw`\n# Deletion Guardrails\n\nLoad this skill when a user asks to delete agents or workflows s"
},
{
"path": "apps/cli/src/application/assistant/skills/index.ts",
"chars": 4718,
"preview": "import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport builtinToolsSkill from \"./builtin-tools/s"
},
{
"path": "apps/cli/src/application/assistant/skills/mcp-integration/skill.ts",
"chars": 12684,
"preview": "export const skill = String.raw`\n# MCP Integration Guidance\n\n**Load this skill proactively** when a user asks for ANY ta"
},
{
"path": "apps/cli/src/application/assistant/skills/workflow-authoring/skill.ts",
"chars": 10914,
"preview": "export const skill = String.raw`\n# Agent and Workflow Authoring\n\nLoad this skill whenever a user wants to inspect, creat"
},
{
"path": "apps/cli/src/application/assistant/skills/workflow-run-ops/skill.ts",
"chars": 3461,
"preview": "export const skill = String.raw`\n# Agent Run Operations\n\nPackage of repeatable commands for running agents, inspecting a"
},
{
"path": "apps/cli/src/application/lib/builtin-tools.ts",
"chars": 18800,
"preview": "import { z, ZodType } from \"zod\";\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { WorkDir as B"
},
{
"path": "apps/cli/src/application/lib/bus.ts",
"chars": 1347,
"preview": "import { RunEvent } from \"../../entities/run-events.js\";\nimport z from \"zod\";\n\nexport interface IBus {\n publish(event"
},
{
"path": "apps/cli/src/application/lib/command-executor.ts",
"chars": 3948,
"preview": "import { exec, execSync } from 'child_process';\nimport { promisify } from 'util';\nimport { getSecurityAllowList, SECURIT"
},
{
"path": "apps/cli/src/application/lib/exec-tool.ts",
"chars": 898,
"preview": "import { ToolAttachment } from \"../../agents/agents.js\";\nimport { z } from \"zod\";\nimport { BuiltinTools } from \"./builti"
},
{
"path": "apps/cli/src/application/lib/id-gen.ts",
"chars": 1198,
"preview": "export interface IMonotonicallyIncreasingIdGenerator {\n next(): Promise<string>;\n}\n\nexport class IdGen implements IMo"
},
{
"path": "apps/cli/src/application/lib/message-queue.ts",
"chars": 1245,
"preview": "import z from \"zod\";\nimport { IMonotonicallyIncreasingIdGenerator } from \"./id-gen.js\";\n\nconst EnqueuedMessage = z.objec"
},
{
"path": "apps/cli/src/application/lib/random-id.ts",
"chars": 218,
"preview": "import { customAlphabet } from 'nanoid';\nconst alphabet = '0123456789abcdefghijklmnopqrstuvwxyz-';\nconst nanoid = custom"
},
{
"path": "apps/cli/src/application/lib/stream-renderer.ts",
"chars": 9968,
"preview": "import { z } from \"zod\";\nimport { RunEvent } from \"../../entities/run-events.js\";\nimport { LlmStepStreamEvent } from \".."
},
{
"path": "apps/cli/src/config/config.ts",
"chars": 446,
"preview": "import path from \"path\";\nimport fs from \"fs\";\nimport { homedir } from \"os\";\n\n// Resolve app root relative to compiled fi"
},
{
"path": "apps/cli/src/config/security.ts",
"chars": 2653,
"preview": "import path from \"path\";\nimport fs from \"fs\";\nimport { WorkDir } from \"./config.js\";\n\nexport const SECURITY_CONFIG_PATH "
},
{
"path": "apps/cli/src/di/container.ts",
"chars": 1466,
"preview": "import { asClass, createContainer, InjectionMode } from \"awilix\";\nimport { FSModelConfigRepo, IModelConfigRepo } from \"."
},
{
"path": "apps/cli/src/entities/example.ts",
"chars": 408,
"preview": "import z from \"zod\"\nimport { Agent } from \"../agents/agents.js\"\nimport { McpServerDefinition } from \"../mcp/schema.js\";\n"
},
{
"path": "apps/cli/src/entities/llm-step-events.ts",
"chars": 1845,
"preview": "import { z } from \"zod\";\nimport { ProviderOptions } from \"./message.js\";\n\nconst BaseEvent = z.object({\n providerOptio"
},
{
"path": "apps/cli/src/entities/message.ts",
"chars": 1604,
"preview": "import { z } from \"zod\";\n\nexport const ProviderOptions = z.record(z.string(), z.record(z.string(), z.json()));\n\nexport c"
},
{
"path": "apps/cli/src/entities/run-events.ts",
"chars": 2497,
"preview": "import { LlmStepStreamEvent } from \"./llm-step-events.js\";\nimport { Message, ToolCallPart } from \"./message.js\";\nimport "
},
{
"path": "apps/cli/src/examples/index.ts",
"chars": 270,
"preview": "import twitterPodcast from './twitter-podcast.json' with { type: 'json' };\nimport { Example } from '../entities/example."
},
{
"path": "apps/cli/src/examples/twitter-podcast.json",
"chars": 20582,
"preview": "{\n \"id\": \"twitter-podcast\",\n \"instructions\": \"This example workflow generates a narrated podcast episode from recent A"
},
{
"path": "apps/cli/src/knowledge/sync_calendar.ts",
"chars": 10136,
"preview": "import fs from 'fs';\nimport path from 'path';\nimport { google } from 'googleapis';\nimport { authenticate } from '@google"
},
{
"path": "apps/cli/src/knowledge/sync_gmail.ts",
"chars": 13879,
"preview": "import fs from 'fs';\nimport path from 'path';\nimport { google } from 'googleapis';\nimport { authenticate } from '@google"
},
{
"path": "apps/cli/src/mcp/mcp.ts",
"chars": 3923,
"preview": "import container from \"../di/container.js\";\nimport { Client } from \"@modelcontextprotocol/sdk/client\";\nimport { SSEClien"
},
{
"path": "apps/cli/src/mcp/repo.ts",
"chars": 1576,
"preview": "import { WorkDir } from \"../config/config.js\";\nimport { McpServerConfig, McpServerDefinition } from \"./schema.js\";\nimpor"
},
{
"path": "apps/cli/src/mcp/schema.ts",
"chars": 1480,
"preview": "import z from \"zod\";\n\nexport const StdioMcpServerConfig = z.object({\n type: z.literal(\"stdio\").optional(),\n comman"
},
{
"path": "apps/cli/src/models/models.ts",
"chars": 3461,
"preview": "import { ProviderV2 } from \"@ai-sdk/provider\";\nimport { createGateway } from \"ai\";\nimport { createOpenAI } from \"@ai-sdk"
},
{
"path": "apps/cli/src/models/repo.ts",
"chars": 2167,
"preview": "import { ModelConfig, Provider } from \"./models.js\";\nimport { WorkDir } from \"../config/config.js\";\nimport fs from \"fs/p"
},
{
"path": "apps/cli/src/runs/lock.ts",
"chars": 494,
"preview": "export interface IRunsLock {\n lock(runId: string): Promise<boolean>;\n release(runId: string): Promise<void>;\n}\n\nex"
},
{
"path": "apps/cli/src/runs/repo.ts",
"chars": 4784,
"preview": "import { Run } from \"./runs.js\";\nimport z from \"zod\";\nimport { IMonotonicallyIncreasingIdGenerator } from \"../applicatio"
},
{
"path": "apps/cli/src/runs/runs.ts",
"chars": 2489,
"preview": "import z from \"zod\";\nimport container from \"../di/container.js\";\nimport { IMessageQueue } from \"../application/lib/messa"
},
{
"path": "apps/cli/src/scripts/migrate-agents.ts",
"chars": 906,
"preview": "import { Agent } from \"../agents/agents.js\";\nimport { IAgentsRepo } from \"../agents/repo.js\";\nimport { WorkDir } from \"."
},
{
"path": "apps/cli/src/server.ts",
"chars": 6143,
"preview": "import { Hono } from 'hono';\nimport { serve } from '@hono/node-server'\nimport { streamSSE } from 'hono/streaming'\nimport"
},
{
"path": "apps/cli/src/shared/prefix-logger.ts",
"chars": 740,
"preview": "// create a PrefixLogger class that wraps console.log with a prefix\n// and allows chaining with a parent logger\nexport c"
},
{
"path": "apps/cli/src/tui/api.ts",
"chars": 6708,
"preview": "import { createParser } from \"eventsource-parser\";\nimport { Agent } from \"../agents/agents.js\";\nimport { AskHumanRespons"
},
{
"path": "apps/cli/src/tui/index.tsx",
"chars": 303,
"preview": "import React from \"react\";\nimport { render } from \"ink\";\nimport { RowboatTui } from \"./ui.js\";\n\nexport function runTui({"
},
{
"path": "apps/cli/src/tui/ui.tsx",
"chars": 41555,
"preview": "import React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { Box, Text, useApp, useInput, useStdou"
},
{
"path": "apps/cli/todo.md",
"chars": 245,
"preview": "runtime\n---\no stream out responses\no terminal logging\no file logging\n- accept initial user input from CLI\n- mcp tool cal"
},
{
"path": "apps/cli/tsconfig.json",
"chars": 423,
"preview": "{\n // Visit https://aka.ms/tsconfig to read more about this file\n \"compilerOptions\": {\n \"rootDir\": \"./src\",\n \"ou"
},
{
"path": "apps/docs/.gitignore",
"chars": 6,
"preview": "site/\n"
},
{
"path": "apps/docs/docs/development/contribution-guide.mdx",
"chars": 2526,
"preview": "---\ntitle: \"Contribution Guide\"\ndescription: \"How to contribute to Rowboat — from bug reports to pull requests.\"\nicon: \""
},
{
"path": "apps/docs/docs/development/roadmap.mdx",
"chars": 105,
"preview": "---\nicon: \"road\"\n---\n\n# Roadmap\n\nExplore the future development plans and upcoming features for Rowboat. "
},
{
"path": "apps/docs/docs/getting-started/introduction.mdx",
"chars": 4651,
"preview": "---\ntitle: \"Introduction\"\ndescription: \"Welcome to the official Rowboat documentation! Rowboat is an open-source AI cowo"
},
{
"path": "apps/docs/docs/getting-started/license.mdx",
"chars": 11621,
"preview": "---\ntitle: \"License\"\nicon: \"file\"\nmode: \"center\"\n# url: \"https://github.com/rowboatlabs/rowboat/blob/main/LICENSE\" ## An"
},
{
"path": "apps/docs/docs/getting-started/quickstart.mdx",
"chars": 814,
"preview": "---\ntitle: \"Quickstart\"\ndescription: \"guide to getting started with rowboat\"\nicon: \"rocket\"\n---\n**Download latest for Ma"
},
{
"path": "apps/docs/docs.json",
"chars": 1489,
"preview": "{\n \"$schema\": \"https://mintlify.com/docs.json\",\n \"theme\": \"maple\",\n \"name\": \"Rowboat\",\n \"description\": \"Rowb"
},
{
"path": "apps/experimental/chat_widget/.dockerignore",
"chars": 78,
"preview": "Dockerfile\n.dockerignore\nnode_modules\nnpm-debug.log\nREADME.md\n.next\n.git\n.env*"
},
{
"path": "apps/experimental/chat_widget/.eslintrc.json",
"chars": 61,
"preview": "{\n \"extends\": [\"next/core-web-vitals\", \"next/typescript\"]\n}\n"
},
{
"path": "apps/experimental/chat_widget/.gitignore",
"chars": 462,
"preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
},
{
"path": "apps/experimental/chat_widget/Dockerfile",
"chars": 2270,
"preview": "# syntax=docker.io/docker/dockerfile:1\n\nFROM node:18-alpine AS base\n\n# Install dependencies only when needed\nFROM base A"
},
{
"path": "apps/experimental/chat_widget/README.md",
"chars": 1450,
"preview": "This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-re"
},
{
"path": "apps/experimental/chat_widget/app/api/bootstrap.js/route.ts",
"chars": 878,
"preview": "export const dynamic = 'force-dynamic'\n\n// Fetch template once when module loads\nconst templatePromise = fetch(process.e"
},
{
"path": "apps/experimental/chat_widget/app/app.tsx",
"chars": 14041,
"preview": "\"use client\";\nimport { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useSearchParams } from \"next/na"
},
{
"path": "apps/experimental/chat_widget/app/globals.css",
"chars": 114,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nbody {\n font-family: Arial, Helvetica, sans-serif;\n}\n"
},
{
"path": "apps/experimental/chat_widget/app/layout.tsx",
"chars": 764,
"preview": "import type { Metadata } from \"next\";\nimport localFont from \"next/font/local\";\nimport \"./globals.css\";\n\nconst geistSans "
},
{
"path": "apps/experimental/chat_widget/app/markdown-content.tsx",
"chars": 2321,
"preview": "import Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nexport default function MarkdownContent({ cont"
},
{
"path": "apps/experimental/chat_widget/app/page.tsx",
"chars": 239,
"preview": "import { Suspense } from 'react';\nimport { App } from './app';\n\nexport const dynamic = 'force-dynamic';\n\nexport default "
},
{
"path": "apps/experimental/chat_widget/app/providers.tsx",
"chars": 288,
"preview": "import * as React from \"react\";\n\n// 1. import `NextUIProvider` component\nimport {NextUIProvider} from \"@nextui-org/react"
},
{
"path": "apps/experimental/chat_widget/next.config.mjs",
"chars": 119,
"preview": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n output: 'standalone',\n};\n\nexport default nextConfig;\n"
},
{
"path": "apps/experimental/chat_widget/package.json",
"chars": 733,
"preview": "{\n \"name\": \"chat-widget\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \""
},
{
"path": "apps/experimental/chat_widget/postcss.config.mjs",
"chars": 135,
"preview": "/** @type {import('postcss-load-config').Config} */\nconst config = {\n plugins: {\n tailwindcss: {},\n },\n};\n\nexport d"
},
{
"path": "apps/experimental/chat_widget/public/bootstrap.template.js",
"chars": 5035,
"preview": "// Split into separate configuration file/module\nconst CONFIG = {\n CHAT_URL: '__CHAT_WIDGET_HOST__',\n API_URL: '__ROWB"
},
{
"path": "apps/experimental/chat_widget/tailwind.config.ts",
"chars": 401,
"preview": "import { nextui } from \"@nextui-org/react\";\nimport type { Config } from \"tailwindcss\";\n\nconst config: Config = {\n conte"
},
{
"path": "apps/experimental/chat_widget/tsconfig.json",
"chars": 598,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n "
},
{
"path": "apps/experimental/simulation_runner/Dockerfile",
"chars": 421,
"preview": "# Use official Python runtime as base image\nFROM python:3.11-slim\n\n# Set working directory in container\nWORKDIR /app\n\n# "
},
{
"path": "apps/experimental/simulation_runner/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "apps/experimental/simulation_runner/db.py",
"chars": 4980,
"preview": "from pymongo import MongoClient\nfrom bson import ObjectId\nimport os\nfrom datetime import datetime, timedelta, timezone\nf"
},
{
"path": "apps/experimental/simulation_runner/requirements.txt",
"chars": 487,
"preview": "annotated-types==0.7.0\nanyio==4.8.0\ncertifi==2025.1.31\ncharset-normalizer==3.4.1\ndistro==1.9.0\ndnspython==2.7.0\nh11==0.1"
},
{
"path": "apps/experimental/simulation_runner/scenario_types.py",
"chars": 1230,
"preview": "from datetime import datetime\nfrom typing import Optional, List, Literal\nfrom pydantic import BaseModel, Field\n\n# Define"
},
{
"path": "apps/experimental/simulation_runner/service.py",
"chars": 4267,
"preview": "import asyncio\nimport logging\nfrom typing import List, Optional\n\n# Updated imports from your new db module and scenario_"
},
{
"path": "apps/experimental/simulation_runner/simulation.py",
"chars": 6527,
"preview": "import asyncio\nimport logging\nfrom typing import List\nimport json\nimport os\nfrom openai import OpenAI\n\nfrom scenario_typ"
},
{
"path": "apps/experimental/tools_webhook/Dockerfile",
"chars": 466,
"preview": "# Use official Python runtime as base image\nFROM python:3.11-slim\n\n# Set working directory in container\nWORKDIR /app\n\n# "
},
{
"path": "apps/experimental/tools_webhook/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "apps/experimental/tools_webhook/app.py",
"chars": 4550,
"preview": "# app.py\n\nimport hashlib\nimport json\nimport logging\nimport os\nfrom functools import wraps\n\nimport jwt\nfrom flask import "
},
{
"path": "apps/experimental/tools_webhook/function_map.py",
"chars": 644,
"preview": "\n\"\"\"\nfunction_map.py\n\nDefines all the callable functions and a mapping from\nstring names to these functions.\n\"\"\"\n\ndef gr"
},
{
"path": "apps/experimental/tools_webhook/requirements.txt",
"chars": 184,
"preview": "blinker==1.9.0\nclick==8.1.8\nFlask==3.1.0\niniconfig==2.0.0\nitsdangerous==2.2.0\nJinja2==3.1.5\nMarkupSafe==3.0.2\npackaging="
},
{
"path": "apps/experimental/tools_webhook/tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "apps/experimental/tools_webhook/tests/test_app.py",
"chars": 2461,
"preview": "# tests/test_app.py\n\nimport json\nimport pytest\nfrom tools_webhook.app import app # If \"sidecar\" is recognized as a pack"
},
{
"path": "apps/experimental/tools_webhook/tests/test_tool_caller.py",
"chars": 1605,
"preview": "# tests/test_tool_caller.py\n\nimport pytest\nfrom tools_webhook.tool_caller import call_tool\nfrom tools_webhook.function_m"
},
{
"path": "apps/experimental/tools_webhook/tool_caller.py",
"chars": 2443,
"preview": "# tool_caller.py\n\nimport inspect\nimport logging\n\nlogger = logging.getLogger(__name__)\n\ndef call_tool(function_name: str,"
},
{
"path": "apps/python-sdk/.gitignore",
"chars": 31,
"preview": "__pycache__/\nvenv/\n.venv/\ndist/"
},
{
"path": "apps/python-sdk/README.md",
"chars": 1945,
"preview": "# Rowboat Python SDK\n\nA Python SDK for interacting with the Rowboat API.\n\n## Installation\n\nYou can install the package u"
},
{
"path": "apps/python-sdk/pyproject.toml",
"chars": 684,
"preview": "[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"rowboat\"\nversion = \"5.0.1\"\n"
},
{
"path": "apps/python-sdk/requirements.txt",
"chars": 177,
"preview": "annotated-types==0.7.0\ncertifi==2024.12.14\ncharset-normalizer==3.4.1\nidna==3.10\npydantic==2.10.5\npydantic_core==2.27.2\nr"
},
{
"path": "apps/python-sdk/src/rowboat/__init__.py",
"chars": 208,
"preview": "from .client import Client\nfrom .schema import (\n ApiMessage,\n UserMessage,\n SystemMessage,\n AssistantMessag"
},
{
"path": "apps/python-sdk/src/rowboat/client.py",
"chars": 2144,
"preview": "from typing import Dict, List, Optional\nimport requests\nfrom .schema import (\n ApiRequest, \n ApiResponse, \n Api"
},
{
"path": "apps/python-sdk/src/rowboat/schema.py",
"chars": 1282,
"preview": "from typing import List, Optional, Union, Literal, Dict\nfrom pydantic import BaseModel\n\nclass SystemMessage(BaseModel):\n"
},
{
"path": "apps/rowboat/.dockerignore",
"chars": 78,
"preview": "Dockerfile\n.dockerignore\nnode_modules\nnpm-debug.log\nREADME.md\n.next\n.git\n.env*"
},
{
"path": "apps/rowboat/.eslintrc.json",
"chars": 40,
"preview": "{\n \"extends\": \"next/core-web-vitals\"\n}\n"
},
{
"path": "apps/rowboat/.gitignore",
"chars": 480,
"preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
},
{
"path": "apps/rowboat/Dockerfile",
"chars": 2191,
"preview": "# syntax=docker.io/docker/dockerfile:1\n\nFROM node:18-alpine AS base\n\n# Install dependencies only when needed\nFROM base A"
},
{
"path": "apps/rowboat/README.md",
"chars": 1390,
"preview": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js"
},
{
"path": "apps/rowboat/app/actions/assistant-templates.actions.ts",
"chars": 9123,
"preview": "\"use server\";\n\nimport { z } from 'zod';\nimport { authCheck } from \"./auth.actions\";\nimport { MongoDBAssistantTemplatesRe"
},
{
"path": "apps/rowboat/app/actions/auth.actions.ts",
"chars": 1340,
"preview": "\"use server\";\nimport { auth0 } from \"../lib/auth0\";\nimport { USE_AUTH } from \"../lib/feature_flags\";\nimport { User } fro"
},
{
"path": "apps/rowboat/app/actions/billing.actions.ts",
"chars": 2735,
"preview": "\"use server\";\nimport {\n authorize,\n logUsage as libLogUsage,\n getBillingCustomer,\n createCustomerPortalSessi"
},
{
"path": "apps/rowboat/app/actions/composio.actions.ts",
"chars": 9172,
"preview": "\"use server\";\nimport { z } from \"zod\";\nimport { ZListResponse } from \"@/src/application/lib/composio/types\";\nimport { ZC"
},
{
"path": "apps/rowboat/app/actions/conversation.actions.ts",
"chars": 1249,
"preview": "\"use server\";\n\nimport { container } from \"@/di/container\";\nimport { IListConversationsController } from \"@/src/interface"
},
{
"path": "apps/rowboat/app/actions/copilot.actions.ts",
"chars": 3526,
"preview": "'use server';\nimport {\n CopilotAPIRequest,\n CopilotChatContext, CopilotMessage,\n DataSourceSchemaForCopilot,\n "
},
{
"path": "apps/rowboat/app/actions/custom-mcp-server.actions.ts",
"chars": 2521,
"preview": "'use server';\n\nimport { z } from 'zod';\nimport { CustomMcpServer } from \"@/src/entities/models/project\";\nimport { getMcp"
},
{
"path": "apps/rowboat/app/actions/data-source.actions.ts",
"chars": 7330,
"preview": "'use server';\nimport { z } from 'zod';\nimport { DataSourceDoc } from \"@/src/entities/models/data-source-doc\";\nimport { D"
},
{
"path": "apps/rowboat/app/actions/job.actions.ts",
"chars": 1278,
"preview": "\"use server\";\n\nimport { container } from \"@/di/container\";\nimport { IListJobsController } from \"@/src/interface-adapters"
},
{
"path": "apps/rowboat/app/actions/playground-chat.actions.ts",
"chars": 1674,
"preview": "'use server';\nimport { z } from 'zod';\nimport { Workflow } from \"../lib/types/workflow_types\";\nimport { Message } from \""
},
{
"path": "apps/rowboat/app/actions/project.actions.ts",
"chars": 9926,
"preview": "'use server';\nimport { z } from 'zod';\nimport { container } from \"@/di/container\";\nimport { redirect } from \"next/naviga"
},
{
"path": "apps/rowboat/app/actions/recurring-job-rules.actions.ts",
"chars": 4036,
"preview": "\"use server\";\n\nimport { container } from \"@/di/container\";\nimport { ICreateRecurringJobRuleController } from \"@/src/inte"
},
{
"path": "apps/rowboat/app/actions/scheduled-job-rules.actions.ts",
"chars": 3506,
"preview": "\"use server\";\n\nimport { container } from \"@/di/container\";\nimport { ICreateScheduledJobRuleController } from \"@/src/inte"
},
{
"path": "apps/rowboat/app/actions/shared-workflow.actions.ts",
"chars": 2184,
"preview": "\"use server\";\n\nimport { z } from \"zod\";\nimport { nanoid } from \"nanoid\";\nimport { Workflow } from \"@/app/lib/types/workf"
},
{
"path": "apps/rowboat/app/actions/twilio.actions.ts",
"chars": 10505,
"preview": "'use server';\n\nimport { TwilioConfigParams, TwilioConfigResponse, TwilioConfig, InboundConfigResponse } from \"../lib/typ"
},
{
"path": "apps/rowboat/app/api/composio/webhook/route.ts",
"chars": 2346,
"preview": "import { PrefixLogger } from \"@/app/lib/utils\";\nimport { container } from \"@/di/container\";\nimport { IHandleComposioWebh"
},
{
"path": "apps/rowboat/app/api/copilot-stream-response/[streamId]/route.ts",
"chars": 2165,
"preview": "import { container } from \"@/di/container\";\nimport { IRunCopilotCachedTurnController } from \"@/src/interface-adapters/co"
},
{
"path": "apps/rowboat/app/api/generated-images/[id]/route.ts",
"chars": 2619,
"preview": "import { NextRequest, NextResponse } from 'next/server';\nimport { S3Client, GetObjectCommand, HeadObjectCommand } from '"
},
{
"path": "apps/rowboat/app/api/me/route.ts",
"chars": 539,
"preview": "import { NextRequest, NextResponse } from 'next/server';\nimport { authCheck } from '@/app/actions/auth.actions';\nimport "
},
{
"path": "apps/rowboat/app/api/stream-response/[streamId]/route.ts",
"chars": 2033,
"preview": "import { container } from \"@/di/container\";\nimport { IRunCachedTurnController } from \"@/src/interface-adapters/controlle"
},
{
"path": "apps/rowboat/app/api/tmp-images/[id]/route.ts",
"chars": 810,
"preview": "import { NextRequest, NextResponse } from 'next/server';\nimport { tempBinaryCache } from '@/src/application/services/tem"
},
{
"path": "apps/rowboat/app/api/twilio/inbound_call/route.ts",
"chars": 3880,
"preview": "import { getResponse } from \"@/src/application/lib/agents-runtime/agents\";\nimport { twilioConfigsCollection, twilioInbou"
},
{
"path": "apps/rowboat/app/api/twilio/turn/[callSid]/route.ts",
"chars": 3016,
"preview": "import { getResponse } from \"@/src/application/lib/agents-runtime/agents\";\nimport { twilioInboundCallsCollection } from "
},
{
"path": "apps/rowboat/app/api/twilio/utils.ts",
"chars": 734,
"preview": "import TwiML from \"twilio/lib/twiml/TwiML\";\nimport VoiceResponse from \"twilio/lib/twiml/VoiceResponse\";\nimport { z } fro"
},
{
"path": "apps/rowboat/app/api/uploads/[fileId]/route.ts",
"chars": 3065,
"preview": "import { NextRequest, NextResponse } from 'next/server';\nimport path from 'path';\nimport fs from 'fs/promises';\nimport f"
},
{
"path": "apps/rowboat/app/api/v1/[projectId]/chat/route.ts",
"chars": 2976,
"preview": "import { NextRequest } from \"next/server\";\nimport { z } from \"zod\";\nimport { ApiResponse } from \"@/app/lib/types/api_typ"
},
{
"path": "apps/rowboat/app/api/widget/v1/chats/[chatId]/close/route.ts",
"chars": 1133,
"preview": "import { NextRequest } from \"next/server\";\nimport { chatsCollection } from \"../../../../../../lib/mongodb\";\nimport { Obj"
},
{
"path": "apps/rowboat/app/api/widget/v1/chats/[chatId]/messages/route.ts",
"chars": 3023,
"preview": "import { NextRequest } from \"next/server\";\nimport { apiV1 } from \"rowboat-shared\";\nimport { chatsCollection, chatMessage"
},
{
"path": "apps/rowboat/app/api/widget/v1/chats/[chatId]/route.ts",
"chars": 1247,
"preview": "import { NextRequest } from \"next/server\";\nimport { apiV1 } from \"rowboat-shared\";\nimport { db } from \"../../../../../li"
},
{
"path": "apps/rowboat/app/api/widget/v1/chats/[chatId]/turn/route.ts",
"chars": 9172,
"preview": "import { NextRequest } from \"next/server\";\nimport { apiV1 } from \"rowboat-shared\";\nimport { chatsCollection, chatMessage"
},
{
"path": "apps/rowboat/app/api/widget/v1/chats/route.ts",
"chars": 3800,
"preview": "import { NextRequest } from \"next/server\";\nimport { db } from \"../../../../lib/mongodb\";\nimport { z } from \"zod\";\nimport"
},
{
"path": "apps/rowboat/app/api/widget/v1/session/guest/route.ts",
"chars": 1034,
"preview": "import { NextRequest } from \"next/server\";\nimport { clientIdCheck } from \"../../utils\";\nimport { SignJWT } from \"jose\";\n"
},
{
"path": "apps/rowboat/app/api/widget/v1/session/user/route.ts",
"chars": 1970,
"preview": "import { NextRequest } from \"next/server\";\nimport { clientIdCheck } from \"../../utils\";\nimport { SignJWT, jwtVerify } fr"
},
{
"path": "apps/rowboat/app/api/widget/v1/utils.ts",
"chars": 2689,
"preview": "import { NextRequest } from \"next/server\";\nimport { z } from \"zod\";\nimport { jwtVerify } from \"jose\";\n\nexport const Sess"
},
{
"path": "apps/rowboat/app/app.tsx",
"chars": 1603,
"preview": "'use client';\nimport Image from 'next/image';\nimport logo from \"@/public/logo.png\";\nimport { useUser } from \"@auth0/next"
},
{
"path": "apps/rowboat/app/billing/app.tsx",
"chars": 15661,
"preview": "'use client';\n\nimport { Progress, Badge, Chip, Spinner } from \"@heroui/react\";\nimport { Button } from \"@/components/ui/b"
},
{
"path": "apps/rowboat/app/billing/callback/page.tsx",
"chars": 573,
"preview": "import { syncWithStripe } from \"@/app/lib/billing\";\nimport { requireBillingCustomer } from '@/app/lib/billing';\nimport {"
},
{
"path": "apps/rowboat/app/billing/layout.tsx",
"chars": 283,
"preview": "import AppLayout from '../projects/layout/components/app-layout';\n\nexport default function Layout({\n children,\n}: Rea"
},
{
"path": "apps/rowboat/app/billing/page.tsx",
"chars": 539,
"preview": "import { requireBillingCustomer } from '../lib/billing';\nimport { BillingPage } from './app';\nimport { getUsage } from '"
},
{
"path": "apps/rowboat/app/browserconfig.xml",
"chars": 246,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n <msapplication>\n <tile>\n <square150x150logo"
},
{
"path": "apps/rowboat/app/components/ui/textarea-with-send.tsx",
"chars": 3904,
"preview": "'use client';\n\nimport { forwardRef, TextareaHTMLAttributes } from 'react';\nimport { Textarea } from '@/components/ui/tex"
},
{
"path": "apps/rowboat/app/composio/oauth2/callback/page.tsx",
"chars": 2324,
"preview": "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { CheckCircle, XCircle } from 'lucide-react';\n\nexport"
},
{
"path": "apps/rowboat/app/globals.css",
"chars": 4347,
"preview": "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap');\n@import 'tailwindcss';\n"
},
{
"path": "apps/rowboat/app/hero.ts",
"chars": 75,
"preview": "// hero.ts\nimport { heroui } from \"@heroui/react\";\nexport default heroui();"
},
{
"path": "apps/rowboat/app/layout.tsx",
"chars": 1015,
"preview": "import \"./globals.css\";\nimport { ThemeProvider } from \"./providers/theme-provider\";\nimport { Inter } from \"next/font/goo"
},
{
"path": "apps/rowboat/app/lib/assistant_templates_seed.ts",
"chars": 8647,
"preview": "import { db } from \"@/app/lib/mongodb\";\nimport { prebuiltTemplates } from \"@/app/lib/prebuilt-cards\";\n\n// Cache to track"
},
{
"path": "apps/rowboat/app/lib/auth.ts",
"chars": 2006,
"preview": "import { z } from \"zod\";\nimport { auth0 } from \"./auth0\";\nimport { User } from \"@/src/entities/models/user\";\nimport { US"
},
{
"path": "apps/rowboat/app/lib/auth0.ts",
"chars": 809,
"preview": "// lib/auth0.js\n\nimport { Auth0Client } from \"@auth0/nextjs-auth0/server\";\n\n// Initialize the Auth0 client \nexport const"
},
{
"path": "apps/rowboat/app/lib/billing.ts",
"chars": 12696,
"preview": "import { z } from 'zod';\nimport { Customer, AuthorizeRequest, AuthorizeResponse, LogUsageRequest, UsageResponse, Custome"
},
{
"path": "apps/rowboat/app/lib/client_utils.ts",
"chars": 3745,
"preview": "import { WorkflowTool, WorkflowAgent, WorkflowPrompt, WorkflowPipeline } from \"./types/workflow_types\";\nimport { Message"
},
{
"path": "apps/rowboat/app/lib/components/atmentions.ts",
"chars": 2749,
"preview": "interface AtMentionItem {\n id: string;\n value: string;\n [key: string]: string; // Add index signature to allow"
},
{
"path": "apps/rowboat/app/lib/components/datasource-icon.tsx",
"chars": 658,
"preview": "import { FileIcon, FilesIcon, FileTextIcon, GlobeIcon } from \"lucide-react\";\n\nexport function DataSourceIcon({\n type "
},
{
"path": "apps/rowboat/app/lib/components/dropdown.tsx",
"chars": 946,
"preview": "import { Select, SelectItem, Button } from \"@heroui/react\";\nimport { ReactNode } from \"react\";\n\nexport interface Dropdow"
},
{
"path": "apps/rowboat/app/lib/components/form-section.tsx",
"chars": 493,
"preview": "import { Divider } from \"@heroui/react\";\nimport { Label } from \"./label\";\n\nexport function FormSection({\n label,\n "
},
{
"path": "apps/rowboat/app/lib/components/form-status-button-old.tsx",
"chars": 288,
"preview": "'use client';\n\nimport { useFormStatus } from \"react-dom\";\nimport { Button, ButtonProps } from \"@heroui/react\";\n\nexport f"
},
{
"path": "apps/rowboat/app/lib/components/form-status-button.tsx",
"chars": 566,
"preview": "'use client';\n\nimport { useFormStatus } from \"react-dom\";\nimport { Button } from \"@/components/ui/button\";\nimport { Butt"
},
{
"path": "apps/rowboat/app/lib/components/icons.tsx",
"chars": 1405,
"preview": "export function WorkflowIcon({\n size = 24,\n strokeWidth = 1,\n}: {\n size?: number;\n strokeWidth?: number;\n}) "
},
{
"path": "apps/rowboat/app/lib/components/input-field.tsx",
"chars": 21020,
"preview": "import { Button, Input, Textarea, Chip, Select, SelectItem, Checkbox } from \"@heroui/react\";\nimport { useEffect, useRef,"
},
{
"path": "apps/rowboat/app/lib/components/label.tsx",
"chars": 142,
"preview": "export function Label({ label }: { label: string }) {\n return <div className=\"text-xs font-medium text-gray-400 upper"
},
{
"path": "apps/rowboat/app/lib/components/markdown-content.tsx",
"chars": 6831,
"preview": "import Markdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport { Match } from './mentions_editor';\n\nexp"
},
{
"path": "apps/rowboat/app/lib/components/mentions-editor.css",
"chars": 1215,
"preview": "@import \"../../globals.css\";\n\n/* Target both edit mode and view mode mentions */\n.mention,\n.ql-editor p span[class*=\"bg-"
},
{
"path": "apps/rowboat/app/lib/components/mentions_editor.tsx",
"chars": 8316,
"preview": "\"use client\"\nimport { useEffect, useRef } from 'react';\nimport Quill, { Delta, Op } from 'quill';\nimport { Mention, Ment"
},
{
"path": "apps/rowboat/app/lib/components/menu-item.tsx",
"chars": 758,
"preview": "import React from 'react';\nimport clsx from 'clsx';\n\ninterface MenuItemProps {\n icon: React.ReactNode;\n children: Reac"
},
{
"path": "apps/rowboat/app/lib/components/message-display.tsx",
"chars": 6001,
"preview": "'use client';\n\nimport { z } from \"zod\";\nimport { Message } from \"@/app/lib/types/types\";\nimport Link from \"next/link\";\n\n"
},
{
"path": "apps/rowboat/app/lib/components/page-section.tsx",
"chars": 431,
"preview": "export function PageSection({\n title,\n children,\n danger = false,\n}: {\n title: string;\n children: React.R"
},
{
"path": "apps/rowboat/app/lib/components/pagination.tsx",
"chars": 506,
"preview": "'use client';\n\nimport { Pagination as NextUiPagination } from \"@heroui/react\";\nimport { usePathname, useRouter } from \"n"
},
{
"path": "apps/rowboat/app/lib/components/reason-badge.tsx",
"chars": 1766,
"preview": "import Link from \"next/link\";\nimport { Turn } from \"@/src/entities/models/turn\";\nimport { z } from \"zod\";\n\nexport functi"
},
{
"path": "apps/rowboat/app/lib/components/structured-list.tsx",
"chars": 1620,
"preview": "import clsx from \"clsx\";\nimport { ActionButton } from \"./structured-panel\";\n\nexport function SectionHeader({ title, chil"
},
{
"path": "apps/rowboat/app/lib/components/structured-panel.tsx",
"chars": 2840,
"preview": "import clsx from \"clsx\";\nimport { InfoIcon } from \"lucide-react\";\nimport { Tooltip } from \"@heroui/react\";\n\nexport funct"
},
{
"path": "apps/rowboat/app/lib/components/typewriter.tsx",
"chars": 1696,
"preview": "\"use client\";\n\nimport { useState, useEffect } from \"react\";\n\nconst phrases = [\n \"Can you help me choose the right pro"
},
{
"path": "apps/rowboat/app/lib/components/user_button.tsx",
"chars": 1718,
"preview": "'use client';\nimport { useUser } from '@auth0/nextjs-auth0';\nimport { Avatar, Dropdown, DropdownItem, DropdownSection, D"
},
{
"path": "apps/rowboat/app/lib/default_tools.ts",
"chars": 1297,
"preview": "import { z } from 'zod';\n\n// Returns the list of built-in tools that should appear by default\n// in the workflow editor "
},
{
"path": "apps/rowboat/app/lib/embedding.ts",
"chars": 512,
"preview": "import { createOpenAI } from \"@ai-sdk/openai\";\n\nconst EMBEDDING_PROVIDER_API_KEY = process.env.EMBEDDING_PROVIDER_API_KE"
},
{
"path": "apps/rowboat/app/lib/feature_flags.ts",
"chars": 1185,
"preview": "export const USE_RAG = process.env.USE_RAG === 'true';\nexport const USE_RAG_UPLOADS = process.env.USE_RAG_UPLOADS === 't"
},
{
"path": "apps/rowboat/app/lib/loadenv.ts",
"chars": 74,
"preview": "import dotenv from 'dotenv'\ndotenv.config({path: [\".env.local\", \".env\"]});"
},
{
"path": "apps/rowboat/app/lib/mcp.ts",
"chars": 1382,
"preview": "import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { SSEClientTransport } from \"@modelcontextpro"
},
{
"path": "apps/rowboat/app/lib/mongodb.ts",
"chars": 1048,
"preview": "import { MongoClient } from \"mongodb\";\nimport { TwilioConfig, TwilioInboundCall } from \"./types/voice_types\";\nimport { z"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/README.md",
"chars": 1834,
"preview": "# Prebuilt Cards Directory\n\nThis directory contains JSON files that define prebuilt assistant templates. These templates"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/customer-support.json",
"chars": 7236,
"preview": "{\n \"agents\": [\n {\n \"name\": \"Product & Delivery Assistant\",\n \"type\": \"conversation\",\n \"description\": \""
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/eisenhower-email-organizer.json",
"chars": 5447,
"preview": "{\n \"agents\": [\n {\n \"name\": \"Classification Agent\",\n \"type\": \"pipeline\",\n \"description\": \"Classifies a"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/github-data-to-spreadsheet.json",
"chars": 32139,
"preview": "{\n \"agents\": [\n {\n \"name\": \"GitHub Stats Hub\",\n \"type\": \"conversation\",\n \"description\": \"Hub agent th"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/github-issue-to-slack.json",
"chars": 6852,
"preview": "{\n \"agents\": [\n {\n \"name\": \"GitHub Issue to Slack Hub\",\n \"type\": \"conversation\",\n \"description\": \"Rec"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/github-pr-to-slack.json",
"chars": 7912,
"preview": "{\n \"agents\": [\n {\n \"name\": \"PR to Slack Agent\",\n \"type\": \"conversation\",\n \"description\": \"Receives PR"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/index.ts",
"chars": 1319,
"preview": "// Static index of prebuilt workflow templates so they are bundled in Vercel\n// If you add/remove a JSON here, update th"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/interview-scheduler.json",
"chars": 23332,
"preview": "{\n \"category\": \"Work Productivity\",\n \"agents\": [\n {\n \"name\": \"Recruitment HR Bot\",\n \"type\": \"conversation"
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/meeting-prep-assistant.json",
"chars": 9085,
"preview": "{\n \"agents\": [\n {\n \"name\": \"Research Guests Agent\",\n \"type\": \"pipeline\",\n \"description\": \"Researches "
},
{
"path": "apps/rowboat/app/lib/prebuilt-cards/reddit-on-slack.json",
"chars": 14822,
"preview": "{\n \"agents\": [\n {\n \"name\": \"Reddit Search Agent\",\n \"type\": \"pipeline\",\n \"description\": \"Searches Redd"
}
]
// ... and 693 more files (download for full content)
About this extraction
This page contains the full source code of the rowboatlabs/rowboat GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 893 files (4.6 MB), approximately 1.3M tokens, and a symbol index with 3392 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.