├── data
└── .gitkeep
├── hatchify
├── __init__.py
├── common
│ ├── __init__.py
│ ├── constants
│ │ └── __init__.py
│ ├── domain
│ │ ├── __init__.py
│ │ ├── entity
│ │ │ ├── __init__.py
│ │ │ ├── function_node_spec.py
│ │ │ ├── graph_execute_data.py
│ │ │ └── init_context.py
│ │ ├── enums
│ │ │ ├── __init__.py
│ │ │ ├── db_type.py
│ │ │ ├── storage_type.py
│ │ │ ├── session_manager_type.py
│ │ │ ├── conversation_mode.py
│ │ │ ├── graph_version_type.py
│ │ │ ├── session_scene.py
│ │ │ ├── message_role.py
│ │ │ ├── agent_category.py
│ │ │ ├── execution_type.py
│ │ │ └── execution_status.py
│ │ ├── event
│ │ │ ├── __init__.py
│ │ │ ├── wrapper_event.py
│ │ │ └── deploy_event.py
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── graph_version.py
│ │ │ ├── web_builder.py
│ │ │ ├── base.py
│ │ │ ├── execution.py
│ │ │ ├── message.py
│ │ │ ├── session.py
│ │ │ └── graph_patch.py
│ │ ├── responses
│ │ │ ├── __init__.py
│ │ │ ├── model_response.py
│ │ │ ├── graph_spec_response.py
│ │ │ ├── tool_response.py
│ │ │ ├── session_response.py
│ │ │ ├── graph_response.py
│ │ │ ├── graph_version_response.py
│ │ │ ├── web_hook.py
│ │ │ └── message_response.py
│ │ ├── structured_output
│ │ │ └── __init__.py
│ │ └── result
│ │ │ ├── __init__.py
│ │ │ └── result.py
│ ├── extensions
│ │ ├── __init__.py
│ │ └── storage
│ │ │ └── __init__.py
│ └── settings
│ │ └── __init__.py
├── core
│ ├── __init__.py
│ ├── factory
│ │ ├── __init__.py
│ │ └── sql_engine_factory.py
│ ├── graph
│ │ ├── __init__.py
│ │ ├── hooks
│ │ │ ├── __init__.py
│ │ │ └── graph_state_hook.py
│ │ ├── nodes
│ │ │ └── __init__.py
│ │ ├── tools
│ │ │ ├── __init__.py
│ │ │ └── math_tool.py
│ │ └── functions
│ │ │ ├── __init__.py
│ │ │ └── echo_function.py
│ ├── manager
│ │ ├── __init__.py
│ │ └── function_manager.py
│ ├── mcp
│ │ └── __init__.py
│ ├── prompts
│ │ └── __init__.py
│ ├── utils
│ │ └── __init__.py
│ └── stream_handler
│ │ ├── __init__.py
│ │ └── event_listener
│ │ ├── __init__.py
│ │ └── event_listener.py
├── launch
│ └── __init__.py
├── utils
│ └── __init__.py
└── business
│ ├── __init__.py
│ ├── api
│ ├── __init__.py
│ └── v1
│ │ ├── __init__.py
│ │ └── models_router.py
│ ├── db
│ ├── __init__.py
│ └── base.py
│ ├── manager
│ ├── __init__.py
│ ├── repository_manager.py
│ └── service_manager.py
│ ├── models
│ └── __init__.py
│ ├── services
│ ├── __init__.py
│ ├── base
│ │ └── __init__.py
│ └── message_service.py
│ ├── utils
│ └── __init__.py
│ ├── middleware
│ └── __init__.py
│ └── repositories
│ ├── __init__.py
│ ├── base
│ └── __init__.py
│ ├── message_repository.py
│ ├── session_repository.py
│ └── execution_repository.py
├── web
├── pnpm-workspace.yaml
├── src
│ ├── types
│ │ ├── vite-env.d.ts
│ │ ├── i18next.d.ts
│ │ ├── api.ts
│ │ ├── resources.ts
│ │ ├── agent.ts
│ │ └── workflow.ts
│ ├── app
│ │ ├── studio
│ │ │ └── components
│ │ │ │ ├── WebsitePanel
│ │ │ │ ├── index.tsx
│ │ │ │ └── WebCreator
│ │ │ │ │ └── types.ts
│ │ │ │ └── ChatPanel
│ │ │ │ ├── chatinput.module.scss
│ │ │ │ ├── index.tsx
│ │ │ │ └── ChatMessageArea
│ │ │ │ ├── ChatLoadingItem.tsx
│ │ │ │ ├── AssistantMessage
│ │ │ │ ├── Progress.tsx
│ │ │ │ └── index.module.scss
│ │ │ │ └── UserMessge.tsx
│ │ └── home
│ │ │ └── components
│ │ │ ├── ToolsLIst.tsx
│ │ │ └── Header.tsx
│ ├── styles
│ │ └── index.css
│ ├── assets
│ │ └── fonts
│ │ │ └── DmSans
│ │ │ ├── rP2Hp2ywxg089UriCZOIHQ.woff2
│ │ │ └── rP2Hp2ywxg089UriCZ2IHSeH.woff2
│ ├── utils
│ │ ├── getPreviewUrl.ts
│ │ ├── index.ts
│ │ ├── toError.ts
│ │ ├── cn.tsx
│ │ └── WaitLock.ts
│ ├── api
│ │ ├── index.ts
│ │ ├── tools.ts
│ │ ├── execution.ts
│ │ └── model.ts
│ ├── main.tsx
│ ├── hooks
│ │ ├── useBodyClassOnOpen.ts
│ │ ├── useTheme.ts
│ │ ├── useStudioParams.ts
│ │ └── useLanguage.ts
│ ├── components
│ │ └── common
│ │ │ ├── Markdown
│ │ │ └── AnswerMakdown.scss
│ │ │ ├── UserProfileHead.tsx
│ │ │ ├── BrandButton
│ │ │ └── brand-button.module.scss
│ │ │ └── ModelSelecter.tsx
│ ├── router.ts
│ ├── stores
│ │ └── workflow
│ │ │ └── index.tsx
│ └── i18n.ts
├── packages
│ └── icons
│ │ ├── .gitignore
│ │ ├── src
│ │ ├── index.ts
│ │ └── type.ts
│ │ ├── preview
│ │ └── main.tsx
│ │ ├── icons
│ │ ├── success-dot.svg
│ │ ├── video-pause-filled.svg
│ │ ├── ai-logos-novita.svg
│ │ ├── minus-circle-filled-M.svg
│ │ ├── reduce.svg
│ │ ├── minus-circle-filled-S.svg
│ │ ├── minus-outline.svg
│ │ ├── dividing-line.svg
│ │ ├── minus-circle-filled-L.svg
│ │ ├── line-divider-v.svg
│ │ ├── credit-basic-filled.svg
│ │ ├── expand-sm.svg
│ │ ├── ai-logos-anthropic.svg
│ │ ├── social-media-logos-mono-x.svg
│ │ ├── social-media-logos-official-x.svg
│ │ ├── title-txt-words.svg
│ │ ├── ai-logos-microsoft.svg
│ │ ├── position-left.svg
│ │ ├── clock-loader-25.svg
│ │ ├── slash-line.svg
│ │ ├── down-md.svg
│ │ ├── line-divider-tilt.svg
│ │ ├── check-md.svg
│ │ ├── position-right.svg
│ │ ├── text.svg
│ │ ├── window-size-change.svg
│ │ ├── add-cross.svg
│ │ ├── minus-circle-outline-M.svg
│ │ ├── add-outline-s.svg
│ │ ├── arrow-down.svg
│ │ ├── arrow-right.svg
│ │ ├── minus-circle-outline-S.svg
│ │ ├── arrow-outline-s-b.svg
│ │ ├── arrow-outline-s-r.svg
│ │ ├── arrow-outline-s-t.svg
│ │ ├── arrow-top.svg
│ │ ├── back-arrow-left.svg
│ │ ├── star-default.svg
│ │ ├── arrow-outline-s-l.svg
│ │ ├── check-mark.svg
│ │ ├── right-outline-l.svg
│ │ ├── right-outline-m.svg
│ │ ├── add-outline-m.svg
│ │ ├── arrow-outline-l-b.svg
│ │ ├── arrow-outline-l-l.svg
│ │ ├── arrow-outline-l-r.svg
│ │ ├── arrow-outline-l-t.svg
│ │ ├── arrow-outline-m-b.svg
│ │ ├── arrow-outline-m-l.svg
│ │ ├── arrow-outline-m-r.svg
│ │ ├── arrow-outline-m-t.svg
│ │ ├── right-outline-s.svg
│ │ ├── back-arrow-line.svg
│ │ ├── clock-loader-125.svg
│ │ ├── arrow-handle-down.svg
│ │ ├── arrow-line-b.svg
│ │ ├── model-grok.svg
│ │ ├── arrow-handle-right.svg
│ │ ├── arrow-line-t.svg
│ │ ├── arrow-handle-left.svg
│ │ ├── arrow-line-tl.svg
│ │ ├── arrow-line-bl.svg
│ │ ├── credit-card.svg
│ │ ├── arrow-line-l.svg
│ │ ├── more-h.svg
│ │ ├── more-v.svg
│ │ ├── arrow-handle-down-right.svg
│ │ ├── arrow-handle-top.svg
│ │ ├── clock-loader-75.svg
│ │ ├── minus-circle-filled.svg
│ │ ├── start-recording.svg
│ │ ├── arrow-handle-down-left.svg
│ │ ├── minus-circle-outline-L.svg
│ │ ├── add-outline-l.svg
│ │ ├── arrow-filled-b.svg
│ │ ├── arrow-filled-l.svg
│ │ ├── arrow-filled-r.svg
│ │ ├── arrow-filled-t.svg
│ │ ├── arrow-line-br.svg
│ │ ├── points-more-ellipsis.svg
│ │ ├── arrow-handle-top-left.svg
│ │ ├── arrow-handle-top-right.svg
│ │ ├── arrow-line-r.svg
│ │ ├── minus-circle-dark.svg
│ │ ├── minus-circle-light.svg
│ │ ├── model-api.svg
│ │ ├── arrow-line-tr.svg
│ │ ├── clock-loader-875.svg
│ │ ├── arrow-turn-left.svg
│ │ ├── close-outline-s.svg
│ │ ├── enter-arrow-back-left.svg
│ │ ├── job-done.svg
│ │ ├── model-claude.svg
│ │ ├── italic-tilt.svg
│ │ ├── flag.svg
│ │ ├── map-navigation.svg
│ │ ├── search.svg
│ │ ├── flag-target.svg
│ │ ├── circle-clock-loader-125.svg
│ │ ├── drawer-control-b.svg
│ │ ├── drawer-control-t.svg
│ │ ├── exclamation-mark-outline.svg
│ │ ├── exclamation-mark.svg
│ │ ├── wrong-cancel-close.svg
│ │ ├── credit-elite-filled.svg
│ │ ├── line-chart-2.svg
│ │ ├── arrow-turn-right.svg
│ │ ├── arrow-turn-back-right.svg
│ │ ├── filter.svg
│ │ ├── arrow-redo-right.svg
│ │ ├── remind-circle-filled.svg
│ │ ├── underline-straight.svg
│ │ ├── arrow-return-left.svg
│ │ ├── text-italic.svg
│ │ ├── job-check.svg
│ │ ├── hamburger-menu-m.svg
│ │ ├── stop-rectangle.svg
│ │ ├── exclamation-mark-circle-filled-error.svg
│ │ ├── exclamation-mark-circle-filled-warning.svg
│ │ ├── linkedIn.svg
│ │ ├── remove-background-outline.svg
│ │ ├── check-green-circle.svg
│ │ ├── add-circle-filled.svg
│ │ ├── clock-loader-375.svg
│ │ ├── close-outline-m.svg
│ │ ├── demo.svg
│ │ ├── linkedin-rectangle.svg
│ │ ├── minus-circle-outline.svg
│ │ ├── right-circle-filled-success.svg
│ │ ├── bold.svg
│ │ ├── close-outline-l.svg
│ │ ├── crop-focus.svg
│ │ ├── image-model-flux-11-pro.svg
│ │ ├── redo.svg
│ │ ├── arrow-line-down.svg
│ │ ├── image-model-flux-11-pro-ultra.svg
│ │ ├── microsoft.svg
│ │ ├── undo.svg
│ │ ├── arrow-line-right.svg
│ │ ├── edit-1.svg
│ │ ├── text-bold.svg
│ │ ├── write-pen.svg
│ │ ├── arrow-line-top.svg
│ │ ├── hamburger-menu-s.svg
│ │ ├── layer-filled.svg
│ │ ├── pill.svg
│ │ ├── arrow-line-left.svg
│ │ ├── circle-clock-loader-50.svg
│ │ ├── contrast.svg
│ │ ├── line-arrow-right.svg
│ │ ├── twitter.svg
│ │ ├── four-squares-filled.svg
│ │ ├── cutting.svg
│ │ ├── history.svg
│ │ ├── line-chart-3.svg
│ │ ├── right-circle-filled.svg
│ │ ├── stroke-partial.svg
│ │ ├── bar-chart-down.svg
│ │ ├── bar-chart-up.svg
│ │ ├── chart-pie.svg
│ │ ├── social-media-logos-mono-youtube.svg
│ │ ├── format-underlined.svg
│ │ ├── ai-logos-groq.svg
│ │ ├── circle-clock-loader-25.svg
│ │ ├── read-aloud.svg
│ │ ├── reduce-disable-circle.svg
│ │ ├── circle-clock-loader-375.svg
│ │ ├── line-arrow-up.svg
│ │ ├── position-top-t.svg
│ │ ├── screen-swith-full.svg
│ │ ├── drawer-control-l.svg
│ │ ├── drawer-control-r.svg
│ │ ├── line-arrow-down.svg
│ │ ├── line-arrow-left.svg
│ │ ├── position-top-b.svg
│ │ ├── screen-swith-collapse.svg
│ │ ├── trends.svg
│ │ ├── zoom-out.svg
│ │ ├── avatar-filled.svg
│ │ ├── right-muti.svg
│ │ ├── clock-loader-50.svg
│ │ ├── currency-yuan.svg
│ │ ├── sort-normal.svg
│ │ ├── trending-down.svg
│ │ ├── arrow-double-outline-l-l.svg
│ │ ├── line-chart-4.svg
│ │ ├── trending-up.svg
│ │ ├── arrow-double-outline-l-r.svg
│ │ ├── arrow-double-outline-m-b.svg
│ │ └── arrow-double-outline-s-b.svg
│ │ ├── index.html
│ │ ├── vite.config.ts
│ │ ├── svgr.config.mjs
│ │ └── tsconfig.json
├── .env.example
├── public
│ └── default-cover.png
├── tsconfig.json
├── index.html
├── .gitignore
├── .dockerignore
├── tsconfig.node.json
├── vite.config.ts
└── tsconfig.app.json
├── resources
└── .env.example
├── main.py
├── Dockerfile
└── pyproject.toml
/data/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/launch/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/db/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/factory/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/graph/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/manager/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/mcp/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/prompts/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/api/v1/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/manager/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/models/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/services/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/constants/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/extensions/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/settings/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/graph/hooks/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/graph/nodes/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/graph/tools/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/middleware/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/repositories/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/services/base/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/entity/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/event/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/graph/functions/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/stream_handler/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/business/repositories/base/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/extensions/storage/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/common/domain/structured_output/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hatchify/core/stream_handler/event_listener/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "packages/*"
3 |
--------------------------------------------------------------------------------
/web/src/types/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/resources/.env.example:
--------------------------------------------------------------------------------
1 | ENVIRONMENT=development
2 | BYPASS_TOOL_CONSENT=true
--------------------------------------------------------------------------------
/web/packages/icons/.gitignore:
--------------------------------------------------------------------------------
1 | # icons
2 | src/icons
3 |
4 | /node_modules
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/web/.env.example:
--------------------------------------------------------------------------------
1 | # Backend API URL for development proxy
2 | VITE_API_TARGET=http://localhost:8000
3 |
--------------------------------------------------------------------------------
/web/public/default-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sider-ai/hatchify/HEAD/web/public/default-cover.png
--------------------------------------------------------------------------------
/web/packages/icons/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './icons';
2 | export * as icons from './icons';
3 | export * from './type';
4 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/db_type.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class DatabasePlatform(str, Enum):
5 | SQLITE = "sqlite"
6 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/storage_type.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class StorageType(str, Enum):
5 | LOCAL = "opendal"
6 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/WebsitePanel/index.tsx:
--------------------------------------------------------------------------------
1 | export default function WebsitePanel() {
2 | return
WebsitePanel
;
3 | }
4 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/session_manager_type.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class SessionManagerType(str, Enum):
5 | LOCAL = "file"
6 |
--------------------------------------------------------------------------------
/web/src/styles/index.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss";
2 | @import "../assets/fonts/DmSans/DmSans.css";
3 | @import "./base.css";
4 | @import "./theme.css";
5 |
--------------------------------------------------------------------------------
/web/src/app/home/components/ToolsLIst.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export default function ToolsLIst() {
4 | return ToolsLIst
;
5 | }
6 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/conversation_mode.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class ConversationMode(str, Enum):
5 | CHAT = "chat"
6 | EDIT = "edit"
7 |
--------------------------------------------------------------------------------
/web/src/assets/fonts/DmSans/rP2Hp2ywxg089UriCZOIHQ.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sider-ai/hatchify/HEAD/web/src/assets/fonts/DmSans/rP2Hp2ywxg089UriCZOIHQ.woff2
--------------------------------------------------------------------------------
/web/src/utils/getPreviewUrl.ts:
--------------------------------------------------------------------------------
1 | export const getPreviewUrl = (workflowId: string) => {
2 | return `${import.meta.env.VITE_API_TARGET}/preview/${workflowId}`;
3 | };
4 |
--------------------------------------------------------------------------------
/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/assets/fonts/DmSans/rP2Hp2ywxg089UriCZ2IHSeH.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sider-ai/hatchify/HEAD/web/src/assets/fonts/DmSans/rP2Hp2ywxg089UriCZ2IHSeH.woff2
--------------------------------------------------------------------------------
/web/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./cn";
2 | export * from "./getPreviewUrl";
3 | export * from "./toError";
4 | export * from "./WaitLock";
5 | export * from "./zip";
6 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/graph_version_type.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class GraphVersionType(str, Enum):
5 | SNAPSHOT = "snapshot"
6 | DRAFT = "draft"
7 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/session_scene.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class SessionScene(str, Enum):
5 | GRAPH_EDIT = "graph_edit"
6 | SITE_GEN = "site_gen"
7 |
--------------------------------------------------------------------------------
/web/src/types/i18next.d.ts:
--------------------------------------------------------------------------------
1 | import type { Resources } from "./resources";
2 |
3 | declare module "i18next" {
4 | interface CustomTypeOptions {
5 | resources: Resources;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/model_response.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel
2 |
3 |
4 | class ModelResponse(BaseModel):
5 | id: str
6 | name: str
7 | description: str
8 |
--------------------------------------------------------------------------------
/web/packages/icons/preview/main.tsx:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom/client';
2 | import App from './index';
3 |
4 | ReactDOM.createRoot(document.getElementById('root')!).render();
5 |
--------------------------------------------------------------------------------
/web/src/utils/toError.ts:
--------------------------------------------------------------------------------
1 | export function toError(error: unknown): Error {
2 | if (error instanceof Error) return error;
3 | return new Error(typeof error === "string" ? error : JSON.stringify(error));
4 | }
5 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/message_role.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class MessageRole(str, Enum):
5 | USER = "user"
6 | ASSISTANT = "assistant"
7 | # SYSTEM = "system"
8 | # TOOL = "tool"
9 |
--------------------------------------------------------------------------------
/hatchify/common/domain/result/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | # @Time : 2025/7/1
4 | # @Author : .*?
5 | # @Email : amashiro2233@gmail.com
6 | # @File : __init__.py
7 | # @Software: PyCharm
8 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/success-dot.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/api/index.ts:
--------------------------------------------------------------------------------
1 | export * as ExecutionApi from "./execution";
2 | export * as ModelApi from "./model";
3 | export * as ToolsApi from "./tools";
4 | export * as WebCreatorApi from "./webcreator";
5 | export * as WorkflowApi from "./workflow";
6 |
--------------------------------------------------------------------------------
/web/src/utils/cn.tsx:
--------------------------------------------------------------------------------
1 | import clsx, { type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | /**
5 | * enhancer tw class
6 | */
7 | /*#__NO_SIDE_EFFECTS__*/
8 | export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs));
9 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/WebsitePanel/WebCreator/types.ts:
--------------------------------------------------------------------------------
1 | export const WebCreatorTab = {
2 | // Code: "code",
3 | Preview: "preview",
4 | Phone: "phone",
5 | } as const;
6 |
7 | export type WebCreatorTab = (typeof WebCreatorTab)[keyof typeof WebCreatorTab];
8 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/graph_spec_response.py:
--------------------------------------------------------------------------------
1 | from typing import Any, Dict
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class GraphSpecResponse(BaseModel):
7 | graph_id: str = Field(..., description="Graph ID")
8 | spec: Dict[str, Any] = Field(..., description="当前 GraphSpec")
9 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/video-pause-filled.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/web/packages/icons/src/type.ts:
--------------------------------------------------------------------------------
1 | import { RefAttributes, SVGProps } from 'react';
2 |
3 | export type SVGAttributes = Partial>;
4 | type ElementAttributes = RefAttributes & SVGAttributes;
5 |
6 | export interface IconProps extends ElementAttributes {
7 | size?: string | number;
8 | }
9 |
--------------------------------------------------------------------------------
/web/src/main.tsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from "react";
2 | import { createRoot } from "react-dom/client";
3 | import "@/styles/index.css";
4 | import "@/i18n.ts";
5 | import App from "@/App.tsx";
6 |
7 | createRoot(document.getElementById("root")!).render(
8 |
9 |
10 | ,
11 | );
12 |
--------------------------------------------------------------------------------
/hatchify/business/db/base.py:
--------------------------------------------------------------------------------
1 | from typing import Protocol, Any, runtime_checkable, TypeVar
2 |
3 | from sqlalchemy.orm import DeclarativeBase
4 |
5 |
6 | @runtime_checkable
7 | class HasId(Protocol):
8 | id: Any
9 |
10 |
11 | class Base(DeclarativeBase):
12 | pass
13 |
14 |
15 | T = TypeVar('T', bound=HasId)
16 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/graph_version.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from pydantic import Field
4 |
5 | from hatchify.common.domain.requests.base import BasePageRequest
6 |
7 |
8 | class PageGraphVersionRequest(BasePageRequest):
9 | graph_id: Optional[str] = Field(default=None, description="按 graph_id 过滤")
10 |
--------------------------------------------------------------------------------
/hatchify/business/repositories/message_repository.py:
--------------------------------------------------------------------------------
1 | from hatchify.business.models.messages import MessageTable
2 | from hatchify.business.repositories.base.generic_repository import GenericRepository
3 |
4 |
5 | class MessageRepository(GenericRepository[MessageTable]):
6 |
7 | def __init__(self):
8 | super().__init__(MessageTable)
9 |
--------------------------------------------------------------------------------
/hatchify/business/repositories/session_repository.py:
--------------------------------------------------------------------------------
1 | from hatchify.business.models.session import SessionTable
2 | from hatchify.business.repositories.base.generic_repository import GenericRepository
3 |
4 |
5 | class SessionRepository(GenericRepository[SessionTable]):
6 |
7 | def __init__(self):
8 | super().__init__(SessionTable)
9 |
--------------------------------------------------------------------------------
/hatchify/business/repositories/execution_repository.py:
--------------------------------------------------------------------------------
1 | from hatchify.business.models.execution import ExecutionTable
2 | from hatchify.business.repositories.base.generic_repository import GenericRepository
3 |
4 |
5 | class ExecutionRepository(GenericRepository[ExecutionTable]):
6 |
7 | def __init__(self):
8 | super().__init__(ExecutionTable)
9 |
--------------------------------------------------------------------------------
/web/src/hooks/useBodyClassOnOpen.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | export function useBodyClassOnOpen(isOpen: boolean, className: string) {
4 | useEffect(() => {
5 | document.body.classList.toggle(className, isOpen);
6 | return () => {
7 | document.body.classList.remove(className);
8 | };
9 | }, [isOpen, className]);
10 | }
11 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/web_builder.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel
2 | from strands.types.content import Messages
3 |
4 |
5 | class WebBuilderConversationRequest(BaseModel):
6 | graph_id: str
7 | messages: Messages
8 | redeploy: bool = True
9 |
10 |
11 | class DeployRequest(BaseModel):
12 | graph_id: str
13 | rebuild: bool = False
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/tool_response.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Any, Optional
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class ToolResponse(BaseModel):
7 | name: str
8 | description: str
9 | input_schema: Dict[str, Any] = Field(default_factory=dict)
10 | output_schema: Optional[Dict[str, Any]] = Field(default=None)
11 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/agent_category.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class AgentCategory(str, Enum):
5 | """Agent 类型
6 |
7 | - GENERAL: 普通 Agent,执行具体任务
8 | - ROUTER: 路由 Agent,根据条件决定下一步执行哪个节点
9 | - ORCHESTRATOR: 编排 Agent,中心化协调所有其他节点
10 | """
11 | GENERAL = "general"
12 | ROUTER = "router"
13 | ORCHESTRATOR = "orchestrator"
14 |
--------------------------------------------------------------------------------
/hatchify/common/domain/entity/function_node_spec.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel, Field
2 |
3 |
4 | class FunctionNode(BaseModel):
5 | name: str = Field(
6 | ...,
7 | description="节点唯一名称(在 Graph 中的 ID,可以自定义)"
8 | )
9 | function_ref: str = Field(
10 | ...,
11 | description="Function 类型(从 function_manager 查找对应的 @tool 函数名)"
12 | )
13 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/base.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class BasePageRequest(BaseModel):
7 | """基础分页请求类,使用 base-1(从1开始)的页码"""
8 | page: int = Field(default=1) # 页码,从1开始
9 | size: int = Field(default=10) # 每页大小
10 | sort: Optional[str] = Field(default=None, description="field1:asc,field2:desc")
11 |
--------------------------------------------------------------------------------
/hatchify/core/graph/functions/echo_function.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel
2 | from strands import tool
3 |
4 |
5 | class EchoResult(BaseModel):
6 | text: str
7 |
8 |
9 | @tool(name="echo_function", description="Echo the input text")
10 | async def echo_function(text: str) -> EchoResult:
11 | """简单的 echo function,用于测试"""
12 | return EchoResult(text=f"[ECHO] {text}")
13 |
--------------------------------------------------------------------------------
/web/src/types/api.ts:
--------------------------------------------------------------------------------
1 | export type ApiExtraResponse = T;
2 |
3 | export type ApiResponse = {
4 | message: string;
5 | code: number;
6 | data: T;
7 | };
8 |
9 | export type WithPagination = {
10 | page: number;
11 | limit: number;
12 | total: number;
13 | pages: number;
14 | hasNext: boolean;
15 | hasPrev: boolean;
16 | list: T[];
17 | };
18 |
--------------------------------------------------------------------------------
/web/src/utils/WaitLock.ts:
--------------------------------------------------------------------------------
1 | export default class WaitLock {
2 | private p: Promise | null = null;
3 | private resolve: (value?: any) => void = () => {};
4 |
5 | lock() {
6 | this.p = new Promise((resolve) => {
7 | this.resolve = resolve;
8 | });
9 | }
10 |
11 | unlock(value?: any) {
12 | this.resolve(value);
13 | }
14 |
15 | wait() {
16 | return this.p;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/execution.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from pydantic import Field
4 |
5 | from hatchify.common.domain.enums.execution_status import ExecutionStatus
6 | from hatchify.common.domain.enums.execution_type import ExecutionType
7 | from hatchify.common.domain.requests.base import BasePageRequest
8 |
9 |
10 | class PageExecutionRequest(BasePageRequest):
11 | ...
--------------------------------------------------------------------------------
/web/packages/icons/icons/ai-logos-novita.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-filled-M.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/web/src/components/common/Markdown/AnswerMakdown.scss:
--------------------------------------------------------------------------------
1 | .cite-popover {
2 | .ant-popover-inner {
3 | display: flex !important;
4 | align-items: stretch !important;
5 | width: 320px !important;
6 | height: 96px !important;
7 | border-radius: 16px !important;
8 | padding: 8px !important;
9 | }
10 |
11 | .ant-popover-inner-content {
12 | flex: 1 1 0% !important;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | hatchify
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/hatchify/business/services/message_service.py:
--------------------------------------------------------------------------------
1 | from hatchify.business.models.messages import MessageTable
2 | from hatchify.business.repositories.message_repository import MessageRepository
3 | from hatchify.business.services.base.generic_service import GenericService
4 |
5 |
6 | class MessageService(GenericService[MessageTable]):
7 |
8 | def __init__(self):
9 | super().__init__(MessageTable, MessageRepository)
10 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/reduce.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-filled-S.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-outline.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/src/hooks/useTheme.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import {
3 | ThemeProviderContext,
4 | type ThemeProviderState,
5 | } from "@/components/provider/ThemeProvider";
6 |
7 | export const useTheme = () => {
8 | const context = useContext(ThemeProviderContext);
9 |
10 | if (context === undefined)
11 | throw new Error("useTheme must be used within a ThemeProvider");
12 |
13 | return context;
14 | };
15 |
--------------------------------------------------------------------------------
/hatchify/common/domain/event/wrapper_event.py:
--------------------------------------------------------------------------------
1 | from typing import Any, Literal
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class AgentEvent(BaseModel):
7 | """Agent 对话事件包装"""
8 | data: Any
9 | type: Literal["agent"] = Field(default="agent", exclude=True)
10 |
11 |
12 | class DeployEvent(BaseModel):
13 | """部署构建事件包装"""
14 | data: Any
15 | type: Literal["deploy"] = Field(default="deploy", exclude=True)
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/dividing-line.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-filled-L.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/hatchify/common/domain/entity/graph_execute_data.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List, Any
2 |
3 | from pydantic import BaseModel
4 |
5 | from hatchify.common.domain.enums.storage_type import StorageType
6 |
7 |
8 | class FileData(BaseModel):
9 | key: str
10 | mime: str
11 | name: str
12 | source: StorageType
13 |
14 |
15 | class GraphExecuteData(BaseModel):
16 | jsons: Dict[str, Any]
17 | files: Dict[str, List[FileData]]
18 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/session_response.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from pydantic import BaseModel, ConfigDict
4 |
5 | from hatchify.common.domain.enums.session_scene import SessionScene
6 |
7 |
8 | class SessionResponse(BaseModel):
9 | id: str
10 | graph_id: str
11 | scene: SessionScene
12 | created_at: datetime
13 | updated_at: datetime
14 |
15 | model_config = ConfigDict(from_attributes=True)
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-divider-v.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/execution_type.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class ExecutionType(str, Enum):
5 | """执行类型 - 对应不同的任务场景"""
6 | WEBHOOK = "webhook" # Webhook 执行 (web_hook_router)
7 | GRAPH_BUILDER = "graph_builder" # Graph 对话 (graph_router)
8 | WEB_BUILDER = "web_builder" # Web Builder 对话 (web_builder_router)
9 | DEPLOY = "deploy" # 部署任务 (web_builder_router deploy)
--------------------------------------------------------------------------------
/web/packages/icons/icons/credit-basic-filled.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/components/common/UserProfileHead.tsx:
--------------------------------------------------------------------------------
1 | import { Settings as SettingsIcon } from "@hatchify/icons";
2 | import { useNavigate } from "react-router";
3 |
4 | export default function UserProfileHead() {
5 | const navigate = useNavigate();
6 | return (
7 |
8 | {
10 | navigate("/settings");
11 | }}
12 | className="size-5 hover:text-primary-1 cursor-pointer"
13 | />
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/web/src/hooks/useStudioParams.ts:
--------------------------------------------------------------------------------
1 | import { useParams } from "react-router";
2 | import { webCreatorTaskId, workflowTaskId } from "@/utils/taskId";
3 |
4 | export const useStudioParams = () => {
5 | const { id } = useParams<{ id: string }>();
6 | const taskIdForWorkflow = id ? workflowTaskId.get(id) : undefined;
7 | const taskIdForWebCreator = id ? webCreatorTaskId.get(id) : undefined;
8 | return { workflowId: id, taskIdForWorkflow, taskIdForWebCreator };
9 | };
10 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/expand-sm.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/ChatPanel/chatinput.module.scss:
--------------------------------------------------------------------------------
1 | .chatInput {
2 | &::-webkit-scrollbar {
3 | width: 4px;
4 | }
5 |
6 | &::-webkit-scrollbar-track {
7 | background: transparent;
8 | }
9 |
10 | /* 滚动条滑块 */
11 | &::-webkit-scrollbar-thumb {
12 | background-color: #3a89ffaf;
13 | border-radius: 2px;
14 | }
15 |
16 | /* 鼠标悬停时的滑块样式 */
17 | &::-webkit-scrollbar-thumb:hover {
18 | background-color: #3a89ff;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/message.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from pydantic import Field
4 |
5 | from hatchify.common.domain.enums.message_role import MessageRole
6 | from hatchify.common.domain.requests.base import BasePageRequest
7 |
8 |
9 | class PageMessageRequest(BasePageRequest):
10 | session_id: Optional[str] = Field(default=None, description="按 session_id 过滤")
11 | role: Optional[MessageRole] = Field(default=None, description="按角色过滤")
12 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/session.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from pydantic import Field
4 |
5 | from hatchify.common.domain.enums.session_scene import SessionScene
6 | from hatchify.common.domain.requests.base import BasePageRequest
7 |
8 |
9 | class PageSessionRequest(BasePageRequest):
10 | graph_id: Optional[str] = Field(default=None, description="按 graph_id 过滤")
11 | scene: Optional[SessionScene] = Field(default=None, description="按 scene 过滤")
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/ai-logos-anthropic.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/web/src/types/resources.ts:
--------------------------------------------------------------------------------
1 | // This file is auto generated by scripts/build-locales-resource.ts
2 | // Don't modify it manually.
3 |
4 | import en from "@/locales/en.json";
5 | import zh_CN from "@/locales/zh_CN.json";
6 |
7 | export const resources = {
8 | en: {
9 | translation: en,
10 | },
11 | zh_CN: {
12 | translation: zh_CN,
13 | },
14 | };
15 |
16 | export type Resources = (typeof resources)["en"];
17 |
18 | export const supportLangs: string[] = ["en", "zh_CN"];
19 |
--------------------------------------------------------------------------------
/hatchify/common/domain/entity/init_context.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Any, Literal
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class InitContext(BaseModel):
7 | base_url: str
8 | repo_url: str
9 | graph_id: str
10 | graph_input_format: Literal["application/json", "multipart/form-data"] = Field(default="application/json")
11 | input_schema: Dict[str, Any] = Field(default_factory=dict)
12 | output_schema: Dict[str, Any] = Field(default_factory=dict)
--------------------------------------------------------------------------------
/web/packages/icons/icons/social-media-logos-mono-x.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/social-media-logos-official-x.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/title-txt-words.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/ChatPanel/index.tsx:
--------------------------------------------------------------------------------
1 | // import { useChatHistoryQuery } from "@/lib/webcreator/useChatHistoryQuery";
2 | import { useChatHistoryQuery } from "@/hooks/useChatHistory";
3 | import ChatInput from "./ChatInput";
4 | import ChatMessageArea from "./ChatMessageArea";
5 |
6 | export default function ChatPanel() {
7 | useChatHistoryQuery();
8 | return (
9 |
10 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/web/src/components/common/BrandButton/brand-button.module.scss:
--------------------------------------------------------------------------------
1 | .brandButton {
2 | background-color: rgba(0, 0, 0, 0.96);
3 |
4 | & > span {
5 | background: linear-gradient(
6 | 103deg,
7 | #ffe3aa 5.37%,
8 | #edf0ff 40.89%,
9 | #aebeff 68.56%,
10 | #bba3ff 91.14%
11 | );
12 | background-clip: text;
13 | -webkit-background-clip: text;
14 | -webkit-text-fill-color: transparent;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/web/src/router.ts:
--------------------------------------------------------------------------------
1 | import { lazy } from "react";
2 | import { createBrowserRouter } from "react-router";
3 | import StudioPage from "@/app/studio/Studio";
4 |
5 | const router = createBrowserRouter([
6 | {
7 | path: "/",
8 | Component: lazy(() => import("@/app/home/Home")),
9 | },
10 | {
11 | path: "/studio/:id",
12 | Component: StudioPage,
13 | },
14 | {
15 | path: "/settings",
16 | Component: lazy(() => import("@/app/settings/Settings")),
17 | },
18 | ]);
19 | export default router;
20 |
--------------------------------------------------------------------------------
/hatchify/core/manager/function_manager.py:
--------------------------------------------------------------------------------
1 | from strands.tools.decorator import DecoratedFunctionTool
2 |
3 | from hatchify.core.factory.tool_factory import ToolRouter
4 | from hatchify.core.graph.functions.echo_function import echo_function
5 |
6 | # 限制 function_router 只接受 DecoratedFunctionTool
7 | # 这确保只有 @tool 装饰的函数可以注册为 Function
8 | # FunctionNodeWrapper 依赖 DecoratedFunctionTool 的特性(如 input_model)
9 | function_router = ToolRouter[DecoratedFunctionTool]()
10 |
11 | function_router.register(echo_function)
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/ai-logos-microsoft.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/position-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/clock-loader-25.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/slash-line.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Environment variables
16 | .env
17 | .env.local
18 | .env.*.local
19 |
20 | # Editor directories and files
21 | .vscode/*
22 | !.vscode/extensions.json
23 | .idea
24 | .DS_Store
25 | *.suo
26 | *.ntvs*
27 | *.njsproj
28 | *.sln
29 | *.sw?
30 |
31 | # TypeScript
32 | *.tsbuildinfo
33 | tsconfig.tsbuildinfo
34 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/down-md.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-divider-tilt.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/check-md.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/position-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/types/agent.ts:
--------------------------------------------------------------------------------
1 | export type AgentDetail = {
2 | name: string;
3 | model: string;
4 | instruction: string;
5 | category: string;
6 | tools: string[];
7 | structured_output_schema: {
8 | type: string;
9 | properties: {
10 | [key: string]: {
11 | type: string;
12 | description: string;
13 | }[];
14 | };
15 | };
16 | };
17 |
18 | export type AgentToolDetail = {
19 | name: string;
20 | description: string;
21 | input_schema: Record;
22 | output_schema: Record;
23 | };
24 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/text.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/src/app/home/components/Header.tsx:
--------------------------------------------------------------------------------
1 | import { TextLogo } from "@hatchify/icons";
2 | import UserProfileHead from "@/components/common/UserProfileHead";
3 |
4 | function Header() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export default Header;
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/window-size-change.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/vite.config.ts:
--------------------------------------------------------------------------------
1 | import react from '@vitejs/plugin-react';
2 | import path from 'path';
3 | import { defineConfig } from 'vite';
4 |
5 | export default defineConfig({
6 | plugins: [react()],
7 | resolve: {
8 | alias: {
9 | '@': path.resolve(__dirname, './preview'),
10 | '@icons': path.resolve(__dirname, './src'),
11 | },
12 | },
13 | css: {
14 | postcss: {
15 | plugins: [],
16 | },
17 | },
18 | server: {
19 | fs: {
20 | // 允许访问上级目录
21 | allow: ['../../..'],
22 | },
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/add-cross.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-outline-M.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 |
3 | import uvicorn
4 |
5 | from hatchify.common.constants.constants import Constants
6 | from hatchify.common.settings.settings import get_hatchify_settings
7 |
8 | settings = get_hatchify_settings()
9 | if __name__ == "__main__":
10 | config = uvicorn.Config(
11 | "hatchify.launch.launch:app",
12 | host=settings.server.host,
13 | port=settings.server.port,
14 | loop="asyncio",
15 | env_file=Constants.Path.EnvPath
16 | )
17 | server = uvicorn.Server(config)
18 | asyncio.run(server.serve())
19 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/add-outline-s.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-outline-S.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-s-b.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-s-r.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-s-t.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-top.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/back-arrow-left.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/star-default.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-s-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/check-mark.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/right-outline-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/right-outline-m.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/add-outline-m.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-l-b.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-l-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-l-r.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-l-t.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-m-b.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-m-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-m-r.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-outline-m-t.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/right-outline-s.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/hatchify/business/manager/repository_manager.py:
--------------------------------------------------------------------------------
1 | from typing import Type, Dict, Any
2 |
3 |
4 | class RepositoryManager:
5 | _instances: Dict[Type, Any] = {}
6 |
7 | @classmethod
8 | def get_repository(cls, repo_class: Type) -> Any:
9 | if repo_class not in cls._instances:
10 | cls._instances[repo_class] = repo_class()
11 | return cls._instances[repo_class]
12 |
13 | @classmethod
14 | def get_repository_dependency(cls, repo_class: Type):
15 | def provider():
16 | return cls.get_repository(repo_class)
17 |
18 | return provider
19 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/graph_response.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import Any, Dict, Optional
3 |
4 | from pydantic import BaseModel, ConfigDict, Field
5 |
6 |
7 | class GraphResponse(BaseModel):
8 | id: str
9 | name: str
10 | description: Optional[str] = Field(default=None)
11 | current_spec: Dict[str, Any]
12 | current_version_id: Optional[int] = Field(default=None)
13 | current_session_id: Optional[str] = Field(default=None)
14 | created_at: datetime
15 | updated_at: datetime
16 |
17 | model_config = ConfigDict(from_attributes=True)
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/back-arrow-line.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/hatchify/business/manager/service_manager.py:
--------------------------------------------------------------------------------
1 | from typing import Type, Dict, Any
2 |
3 |
4 | class ServiceManager:
5 | _instances: Dict[Type, Any] = {}
6 |
7 | @classmethod
8 | def get_service(cls, service_class: Type) -> Any:
9 | if service_class not in cls._instances:
10 | cls._instances[service_class] = service_class()
11 | return cls._instances[service_class]
12 |
13 | @classmethod
14 | def get_service_dependency(cls, service_class: Type):
15 | def provider():
16 | return cls.get_service(service_class)
17 |
18 | return provider
19 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/clock-loader-125.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/src/stores/workflow/index.tsx:
--------------------------------------------------------------------------------
1 | import { create } from "zustand";
2 | import { devtools } from "zustand/middleware";
3 | import type { ChatSlice } from "./slices/chatSlice";
4 | import { createChatSlice } from "./slices/chatSlice";
5 | import type { UiSlice } from "./slices/uiSlice";
6 | import { createUiSlice } from "./slices/uiSlice";
7 |
8 | type WorkflowStoreState = ChatSlice & UiSlice;
9 |
10 | const useWorkflowStore = create()(
11 | devtools((...a) => ({
12 | ...createChatSlice(...a),
13 | ...createUiSlice(...a),
14 | })),
15 | );
16 |
17 | export default useWorkflowStore;
18 |
--------------------------------------------------------------------------------
/web/.dockerignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | node_modules
3 | **/node_modules
4 |
5 | # Build outputs
6 | dist
7 | **/dist
8 | .vite
9 | .turbo
10 |
11 | # Development files
12 | .git
13 | .github
14 | *.log
15 | npm-debug.log*
16 | pnpm-debug.log*
17 | yarn-debug.log*
18 | yarn-error.log*
19 |
20 | # IDE
21 | .vscode
22 | .idea
23 | *.swp
24 | *.swo
25 | *~
26 | .DS_Store
27 |
28 | # Test coverage
29 | coverage
30 | .nyc_output
31 |
32 | # Environment files
33 | .env
34 | .env.local
35 | .env.development
36 | .env.production
37 | .env*.local
38 |
39 | # Misc
40 | *.md
41 | !README.md
42 | .gitignore
43 | .editorconfig
44 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-down.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-b.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/model-grok.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-right.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-t.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/ChatPanel/ChatMessageArea/ChatLoadingItem.tsx:
--------------------------------------------------------------------------------
1 | import { Loading } from "@hatchify/icons";
2 |
3 | function ChatLoadingItem() {
4 | return (
5 |
16 | );
17 | }
18 |
19 | export default ChatLoadingItem;
20 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-left.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-tl.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-bl.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/credit-card.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-l.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/more-h.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/more-v.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-down-right.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-top.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/clock-loader-75.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-filled.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/start-recording.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-down-left.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-outline-L.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/add-outline-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-filled-b.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-filled-l.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-filled-r.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-filled-t.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-br.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/points-more-ellipsis.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/web/src/components/common/ModelSelecter.tsx:
--------------------------------------------------------------------------------
1 | import { Select } from "antd";
2 | import { ModelApi } from "@/api";
3 |
4 | export default function ModelSelecter({
5 | value,
6 | onChange,
7 | }: {
8 | value: string;
9 | onChange: (value: string) => void;
10 | }) {
11 | const { modelList } = ModelApi.useModelList();
12 |
13 | const modelOptions = modelList.map((model) => ({
14 | label: model.id,
15 | value: model.id,
16 | }));
17 |
18 | return (
19 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-top-left.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-handle-top-right.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/graph_version_response.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | from pydantic import BaseModel, ConfigDict, Field
4 |
5 | from hatchify.common.domain.enums.graph_version_type import GraphVersionType
6 |
7 |
8 | class GraphVersionResponse(BaseModel):
9 | id: int
10 | graph_id: str
11 | version: int | None
12 | type: GraphVersionType
13 | spec: dict
14 | comment: str | None = Field(default=None)
15 | parent_version_id: int | None = Field(default=None)
16 | branch_session_id: str | None = Field(default=None)
17 | created_at: datetime
18 |
19 | model_config = ConfigDict(from_attributes=True)
20 |
--------------------------------------------------------------------------------
/web/src/hooks/useLanguage.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react";
2 | import { useTranslation } from "react-i18next";
3 | import { supportLangs } from "@/types/resources";
4 |
5 | export function useLanguage() {
6 | const { i18n, t } = useTranslation();
7 |
8 | const changeLanguage = useCallback(
9 | (language: string) => {
10 | // if (supportLangs.includes(language))
11 | i18n.changeLanguage(language);
12 | // else throw new Error(`Unsupported language: ${language}`)
13 | },
14 | [i18n],
15 | );
16 |
17 | return {
18 | currentLanguage: i18n.language,
19 | supportedLanguages: supportLangs,
20 | changeLanguage,
21 | t,
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-r.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-light.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/model-api.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-tr.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/clock-loader-875.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import i18n from "i18next";
2 | import { initReactI18next } from "react-i18next";
3 | import { resources } from "@/types/resources";
4 |
5 | const LANGUAGE_KEY = "language";
6 |
7 | i18n.use(initReactI18next).init({
8 | lng: localStorage.getItem(LANGUAGE_KEY) || "en",
9 | fallbackLng: "en",
10 | resources,
11 | interpolation: {
12 | escapeValue: false,
13 | },
14 | });
15 |
16 | i18n.on("languageChanged", (lng) => {
17 | localStorage.setItem(LANGUAGE_KEY, lng);
18 | });
19 |
20 | window.addEventListener("storage", (event) => {
21 | if (event.key === LANGUAGE_KEY && event.newValue)
22 | i18n.changeLanguage(event.newValue);
23 | });
24 |
25 | export default i18n;
26 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-turn-left.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/close-outline-s.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/enter-arrow-back-left.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/job-done.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/model-claude.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/hatchify/common/domain/event/deploy_event.py:
--------------------------------------------------------------------------------
1 | from typing import Literal
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class ProgressEvent(BaseModel):
7 | """部署进度事件"""
8 | type: Literal["progress"] = Field(default="progress", exclude=True)
9 | stage: Literal["checking", "installing", "building", "deploying"]
10 | message: str
11 |
12 |
13 | class LogEvent(BaseModel):
14 | """构建日志事件"""
15 | type: Literal["log"] = Field(default="log", exclude=True)
16 | content: str
17 |
18 |
19 | class DeployResultEvent(BaseModel):
20 | """部署完成事件"""
21 | type: Literal["deploy_result"] = Field(default="deploy_result", exclude=True)
22 | preview_url: str
23 | message: str
--------------------------------------------------------------------------------
/hatchify/common/domain/result/result.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | # @Time : 2025/7/1
4 | # @Author : .*?
5 | # @Email : amashiro2233@gmail.com
6 | # @File : result
7 | # @Software: PyCharm
8 | from pydantic import BaseModel
9 |
10 |
11 | class Result[T](BaseModel):
12 | code: int
13 | message: str
14 | data: T | None = None
15 |
16 | @classmethod
17 | def ok(cls, data: T | None = None, code: int = 200, message: str = "Success"):
18 | return cls(code=code, message=message, data=data)
19 |
20 | @classmethod
21 | def error(cls, code: int = 500, message: str = "Internal Server Error"):
22 | return cls(code=code, message=message)
23 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/italic-tilt.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/flag.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/map-navigation.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/search.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/flag-target.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/src/api/tools.ts:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import request, { HyperRequest } from "@/lib/request";
3 | import type { AgentToolDetail } from "@/types/agent";
4 | import type { ApiResponse } from "@/types/api";
5 |
6 | const requestAgent = HyperRequest.prefixExtend("/tools", request);
7 |
8 | export const getAgentToolsList = () => {
9 | return requestAgent.get>("/all");
10 | };
11 |
12 | export const useAgentToolsList = () => {
13 | return useQuery({
14 | queryKey: ["all-agent-tools"],
15 | queryFn: () => getAgentToolsList(),
16 | select(data) {
17 | if (data?.data) {
18 | return data.data;
19 | }
20 | return [];
21 | },
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/circle-clock-loader-125.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/drawer-control-b.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/drawer-control-t.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/exclamation-mark-outline.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/exclamation-mark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/wrong-cancel-close.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/hatchify/common/domain/requests/graph_patch.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List, Optional
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class AgentPatch(BaseModel):
7 | model: Optional[str] = Field(default=None, description="LLM 模型")
8 | instruction: Optional[str] = Field(default=None, description="系统指令")
9 | tools: Optional[List[str]] = Field(default=None, description="工具列表")
10 |
11 |
12 | class AgentsPatch(BaseModel):
13 | update: Optional[Dict[str, AgentPatch]] = Field(
14 | default=None,
15 | description="更新 Agent,key=name,value=要修改的字段"
16 | )
17 |
18 |
19 | class GraphSpecPatchRequest(BaseModel):
20 | agents: Optional[AgentsPatch] = Field(default=None, description="Agent 节点操作")
--------------------------------------------------------------------------------
/web/packages/icons/icons/credit-elite-filled.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-chart-2.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-turn-right.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/src/types/workflow.ts:
--------------------------------------------------------------------------------
1 | import type { AgentDetail } from "./agent";
2 |
3 | export type WorkflowListItem = WorkflowDetail;
4 |
5 | export type WorkflowDetail = {
6 | id: string;
7 | name: string;
8 | description: string;
9 | current_spec: {
10 | agents: AgentDetail[];
11 | nodes: string[];
12 | edges: {
13 | from_node: string;
14 | to_node: string;
15 | }[];
16 | entry_point: string;
17 | input_schema: Record;
18 | output_schema: Record;
19 | };
20 | current_version_id: number;
21 | created_at: string;
22 | updated_at: string;
23 | };
24 |
25 | export type WorkflowProcessor = {
26 | instance_name: string;
27 | processor_type: string;
28 | input_mapping: Record;
29 | };
30 |
--------------------------------------------------------------------------------
/hatchify/common/domain/enums/execution_status.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class ExecutionStatus(str, Enum):
5 | """
6 | 执行状态 - 对应 StreamEvent 生命周期
7 |
8 | 生命周期映射:
9 | - PENDING: 任务创建但未开始
10 | - RUNNING: 收到 StartEvent
11 | - COMPLETED: 收到 DoneEvent(reason="completed")
12 | - CANCELLED: 收到 DoneEvent(reason="cancel") 或 CancelEvent
13 | - FAILED: 收到 DoneEvent(reason="error") 或 ErrorEvent
14 | """
15 | PENDING = "pending" # 等待中
16 | RUNNING = "running" # 处理中 (StartEvent)
17 | COMPLETED = "completed" # 完成 (DoneEvent: completed)
18 | FAILED = "failed" # 失败 (DoneEvent: error / ErrorEvent)
19 | CANCELLED = "cancelled" # 已取消 (DoneEvent: cancel / CancelEvent)
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-turn-back-right.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/filter.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-redo-right.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/remind-circle-filled.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/underline-straight.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/web_hook.py:
--------------------------------------------------------------------------------
1 | from typing import Literal, Dict, Any, List, Optional
2 |
3 | from pydantic import BaseModel, Field
4 |
5 |
6 | class ExecutionResponse(BaseModel):
7 | graph_id: Optional[str] = Field(default=None)
8 | session_id: Optional[str] = Field(default=None)
9 | execution_id: str
10 |
11 |
12 | class WebHookInfoResponse(BaseModel):
13 | graph_id: str
14 | input_type: Literal["application/json", "multipart/form-data"] = Field(default="application/json")
15 | data_fields: List[str] = Field(default_factory=list)
16 | file_fields: List[str] = Field(default_factory=list)
17 | input_schema: Dict[str, Any] = Field(default_factory=dict)
18 | output_schema: Dict[str, Any] = Field(default_factory=dict)
19 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-return-left.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/text-italic.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/job-check.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/hamburger-menu-m.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/stop-rectangle.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/svgr.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | icon: true,
3 | typescript: true,
4 | prettier: false,
5 | memo: false,
6 | plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx'],
7 | svgoConfig: {
8 | plugins: [
9 | {
10 | name: 'preset-default',
11 | params: {
12 | overrides: {
13 | removeViewBox: false,
14 | },
15 | },
16 | },
17 | {
18 | name: 'prefixIds',
19 | params: {
20 | delim: '',
21 | prefix: 'icon-${componentName}-${uniqueID}-',
22 | },
23 | },
24 | ],
25 | },
26 | svgProps: {
27 | fill: '{color}', // SVGR 会将其转换为 fill={color}
28 | width: '{size}', // 这里的表达式要放在 {} 内部
29 | height: '{size}',
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/web/src/api/execution.ts:
--------------------------------------------------------------------------------
1 | import request, { HyperRequest } from "@/lib/request";
2 | import type { ApiResponse } from "@/types/api";
3 |
4 | const requestExecution = HyperRequest.prefixExtend("/executions", request);
5 |
6 | export const getTaskExectionDetailByID = (id: string) => {
7 | return requestExecution.get>(
8 | `/get_by_id/${id}`,
9 | );
10 | };
11 |
12 | type TaskExecutionDetail = {
13 | id: string;
14 | type: "graph_builder" | "webhook" | "web_builder" | "deploy";
15 | status: "completed" | "pending" | "running" | "failed" | "cancelled";
16 | error: string | null;
17 | graph_id: string;
18 | session_id: string;
19 | created_at: string;
20 | started_at: string;
21 | completed_at: string;
22 | updated_at: string;
23 | };
24 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/ChatPanel/ChatMessageArea/AssistantMessage/Progress.tsx:
--------------------------------------------------------------------------------
1 | import { CheckMark, Loading } from "@hatchify/icons";
2 | import { memo } from "react";
3 | import type { MessageItem, MessageItemType } from "@/types/chat";
4 |
5 | function Progress({
6 | item,
7 | isLoading: _,
8 | }: {
9 | item: Extract;
10 | isLoading: boolean;
11 | }) {
12 | return (
13 |
14 | {item.progress === 100 ? (
15 |
16 | ) : (
17 |
18 | )}
19 | {item.progress}%
20 |
21 | );
22 | }
23 |
24 | export default memo(Progress);
25 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/exclamation-mark-circle-filled-error.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/exclamation-mark-circle-filled-warning.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/src/api/model.ts:
--------------------------------------------------------------------------------
1 | import { useQuery } from "@tanstack/react-query";
2 | import _request, { HyperRequest } from "@/lib/request";
3 | import type { ApiResponse } from "@/types/api";
4 |
5 | const request = HyperRequest.prefixExtend("/models", _request);
6 |
7 | export function getModelList() {
8 | return request.get<
9 | ApiResponse<{ id: string; name: string; description: string }[]>
10 | >("/all");
11 | }
12 |
13 | export const useModelList = () => {
14 | const { data, isLoading, ...rest } = useQuery({
15 | queryKey: ["modelList"],
16 | queryFn: () => getModelList(),
17 | select(data) {
18 | if (data.data) return data.data;
19 | return [];
20 | },
21 | });
22 |
23 | return {
24 | modelList: data ?? [],
25 | isLoading,
26 | ...rest,
27 | };
28 | };
29 |
--------------------------------------------------------------------------------
/web/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4 | "target": "ES2023",
5 | "lib": ["ES2023"],
6 | "module": "ESNext",
7 | "types": ["node"],
8 | "skipLibCheck": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "bundler",
12 | "allowImportingTsExtensions": true,
13 | "verbatimModuleSyntax": true,
14 | "moduleDetection": "force",
15 | "noEmit": true,
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "erasableSyntaxOnly": true,
22 | "noFallthroughCasesInSwitch": true,
23 | "noUncheckedSideEffectImports": true
24 | },
25 | "include": ["vite.config.ts"]
26 | }
27 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/linkedIn.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/remove-background-outline.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # ----------------------------
2 | # builder
3 | # ----------------------------
4 | FROM python:3.13.5-slim AS builder
5 |
6 | ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=0
7 |
8 | WORKDIR /app
9 |
10 | RUN pip install uv
11 |
12 | COPY pyproject.toml /app
13 |
14 | RUN uv lock && uv sync --frozen --no-dev
15 | # ----------------------------
16 | # runtime
17 | # ----------------------------
18 | FROM python:3.13.5-slim
19 |
20 | RUN apt-get update && apt-get install -y git npm
21 |
22 | WORKDIR /app
23 | VOLUME /app/resources
24 | VOLUME /app/data
25 |
26 | ENV PATH="/app/.venv/bin:${PATH}"
27 |
28 | COPY . /app
29 | COPY --from=builder /usr/local/bin /usr/local/bin
30 | COPY --from=builder /app/.venv /app/.venv
31 |
32 | CMD ["python", "main.py"]
33 |
--------------------------------------------------------------------------------
/hatchify/core/stream_handler/event_listener/event_listener.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 |
3 | from hatchify.common.domain.event.base_event import StreamEvent
4 |
5 |
6 | class EventListener(ABC):
7 | """
8 | 事件监听器接口
9 |
10 | 所有事件监听器都需要实现此接口
11 | 支持实例级注册,每个 StreamHandler 可以选择性启用监听器
12 | """
13 |
14 | @abstractmethod
15 | async def on_event(self, execution_id: str, event: StreamEvent):
16 | """
17 | 事件回调方法
18 |
19 | Args:
20 | execution_id: 执行ID
21 | event: 流事件
22 | """
23 | pass
24 |
25 | @property
26 | @abstractmethod
27 | def name(self) -> str:
28 | """
29 | 监听器名称(用于日志和调试)
30 |
31 | Returns:
32 | 监听器的唯一标识名称
33 | """
34 | pass
--------------------------------------------------------------------------------
/web/packages/icons/icons/check-green-circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/add-circle-filled.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/clock-loader-375.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/close-outline-m.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/demo.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/linkedin-rectangle.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/minus-circle-outline.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/right-circle-filled-success.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/bold.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/close-outline-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/crop-focus.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/image-model-flux-11-pro.svg:
--------------------------------------------------------------------------------
1 |
26 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/redo.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-down.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/image-model-flux-11-pro-ultra.svg:
--------------------------------------------------------------------------------
1 |
26 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/microsoft.svg:
--------------------------------------------------------------------------------
1 |
26 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/undo.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./dist",
4 | "composite": true,
5 | "verbatimModuleSyntax": false,
6 | "jsx": "react-jsx",
7 | "declaration": true,
8 | "declarationMap": true,
9 | "esModuleInterop": true,
10 | "incremental": true,
11 | "isolatedModules": true,
12 | "lib": ["ESNext", "DOM", "DOM.Iterable"],
13 | "module": "NodeNext",
14 | "moduleDetection": "force",
15 | "moduleResolution": "NodeNext",
16 | "noUncheckedIndexedAccess": true,
17 | "resolveJsonModule": true,
18 | "skipLibCheck": true,
19 | "strict": true,
20 | "target": "ES2015",
21 | "paths": {
22 | "@/*": ["./preview/*"],
23 | "@icons/*": ["./src/*"]
24 | }
25 | },
26 | "exclude": ["**/node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/web/vite.config.ts:
--------------------------------------------------------------------------------
1 | import path from "node:path";
2 | import tailwindcss from "@tailwindcss/vite";
3 | import react from "@vitejs/plugin-react";
4 | import { defineConfig, loadEnv, type PluginOption } from "vite";
5 |
6 | // https://vite.dev/config/
7 | export default defineConfig(({ mode }) => {
8 | const env = loadEnv(mode, process.cwd(), "");
9 | const apiTarget = env.VITE_API_TARGET || "http://localhost:8000";
10 |
11 | return {
12 | plugins: [react(), tailwindcss() as PluginOption],
13 | resolve: {
14 | alias: {
15 | "@": path.resolve(__dirname, "src"),
16 | },
17 | },
18 | server: {
19 | proxy: {
20 | "/api": {
21 | target: apiTarget,
22 | changeOrigin: true,
23 | secure: false,
24 | rewrite: (path) => path,
25 | },
26 | },
27 | },
28 | };
29 | });
30 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-right.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/edit-1.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/text-bold.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/write-pen.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/ChatPanel/ChatMessageArea/AssistantMessage/index.module.scss:
--------------------------------------------------------------------------------
1 | @mixin blink-cursor() {
2 | animation: blink 1s steps(5, start) infinite;
3 | animation: pulseSize 1.25s ease-in-out infinite;
4 | content: "●";
5 | display: inline-flex;
6 | font-size: 12px;
7 | font-family: "Noto Sans SC";
8 | margin-inline-start: 0.25em;
9 | vertical-align: baseline;
10 | }
11 |
12 | .blinkContainer {
13 | :global(.markdown-body) {
14 | & > :not(ol):not(ul):not(pre):not(.table-with-header):not(.code-block-inner):last-child,
15 | & > ol:last-child > li:last-child,
16 | // & > pre:last-child code,
17 | & > ul:last-child > li:last-child,
18 | & > p:last-child {
19 | &::after {
20 | @include blink-cursor;
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-top.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/hamburger-menu-s.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/layer-filled.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/pill.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-line-left.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/hatchify/core/factory/sql_engine_factory.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from sqlalchemy.ext.asyncio import create_async_engine
4 |
5 | from hatchify.common.domain.enums.db_type import DatabasePlatform
6 | from hatchify.common.settings.settings import get_hatchify_settings
7 |
8 | settings = get_hatchify_settings()
9 |
10 | db = settings.db
11 |
12 |
13 | def create_sql_engine():
14 | match db.platform:
15 | case DatabasePlatform.SQLITE | _:
16 | sqlite_cfg = db.sqlite
17 | return create_async_engine(
18 | sqlite_cfg.url,
19 | echo=sqlite_cfg.echo,
20 | pool_pre_ping=sqlite_cfg.pool_pre_ping,
21 | connect_args=sqlite_cfg.connect_args,
22 | json_serializer=lambda obj: json.dumps(obj, ensure_ascii=False),
23 | )
24 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/circle-clock-loader-50.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/contrast.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-arrow-right.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/twitter.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/four-squares-filled.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "hatchify"
3 | version = "0.1.0"
4 | description = "Add your description here"
5 | readme = "README.md"
6 | requires-python = ">=3.13"
7 | dependencies = [
8 | "aiofiles>=25.1.0",
9 | "aiosqlite>=0.21.0",
10 | "fastapi>=0.121.2",
11 | "fastapi-pagination>=0.15.0",
12 | "google-genai>=1.52.0",
13 | "greenlet>=3.2.4",
14 | "instructor[litellm]>=1.13.0",
15 | "litellm>=1.80.0",
16 | "loguru>=0.7.3",
17 | "opendal>=0.46.0",
18 | "psycopg[binary,pool]>=3.2.12",
19 | "pydantic-settings[yaml]>=2.12.0",
20 | "sqlalchemy[asyncio]>=2.0.44",
21 | "strands-agents>=1.16.0",
22 | "strands-agents-tools>=0.2.16",
23 | "uvicorn>=0.38.0",
24 | ]
25 |
26 | [project.optional-dependencies]
27 | volcengine = [
28 | "volcengine-python-sdk[ark]>=4.0.43",
29 | ]
30 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/cutting.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/history.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-chart-3.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/right-circle-filled.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/stroke-partial.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/bar-chart-down.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/bar-chart-up.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/chart-pie.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/social-media-logos-mono-youtube.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/format-underlined.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/web/src/app/studio/components/ChatPanel/ChatMessageArea/UserMessge.tsx:
--------------------------------------------------------------------------------
1 | import { memo } from "react";
2 | import { type ChatHistory, type MessageItem, MessageItemType } from "@/types/chat";
3 |
4 | function UserMessge({ message }: { message: ChatHistory }) {
5 | return (
6 |
7 |
13 | {message.content.map((item: MessageItem) => {
14 | if (item.type === MessageItemType.TEXT) {
15 | return
{item.text}
;
16 | }
17 | return null;
18 | })}
19 |
20 |
21 | );
22 | }
23 |
24 | export default memo(UserMessge);
25 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/ai-logos-groq.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/circle-clock-loader-25.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/read-aloud.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/reduce-disable-circle.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/hatchify/business/api/v1/models_router.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from fastapi import APIRouter
4 |
5 | from hatchify.common.domain.responses.model_response import ModelResponse
6 | from hatchify.common.domain.result.result import Result
7 | from hatchify.core.manager.model_card_manager import model_card_manager
8 |
9 | model_router = APIRouter(prefix="/models")
10 |
11 |
12 | @model_router.get("/all")
13 | async def all_tools() -> Result[List[ModelResponse]]:
14 | try:
15 | return Result.ok(
16 | data=[
17 | ModelResponse(id=model.id, name=model.name, description=model.description)
18 | for model in model_card_manager.get_all_models()
19 | ]
20 | )
21 | except Exception as e:
22 | msg = f"{type(e).__name__}: {e}"
23 | return Result.error(message=msg)
24 |
--------------------------------------------------------------------------------
/hatchify/common/domain/responses/message_response.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import List, Dict, Any
3 |
4 | from pydantic import BaseModel, ConfigDict, Field, field_validator
5 |
6 | from hatchify.common.domain.enums.message_role import MessageRole
7 |
8 |
9 | class MessageResponse(BaseModel):
10 | id: str
11 | session_id: str
12 | role: MessageRole
13 | content: List[Dict[str, Any]]
14 | token_usage: Dict[str, Any] = Field(default_factory=dict)
15 | meta_data: Dict[str, Any] = Field(default_factory=dict)
16 | created_at: datetime
17 |
18 | model_config = ConfigDict(from_attributes=True)
19 |
20 | @field_validator('token_usage', 'meta_data', mode='before')
21 | @classmethod
22 | def convert_none_to_dict(cls, v):
23 | """将 None 值转换为空字典"""
24 | return v if v is not None else {}
25 |
--------------------------------------------------------------------------------
/hatchify/core/graph/hooks/graph_state_hook.py:
--------------------------------------------------------------------------------
1 | from typing import Any
2 |
3 | from strands.experimental.hooks.multiagent import AfterNodeCallEvent, BeforeNodeCallEvent
4 | from strands.hooks import HookProvider, HookRegistry
5 |
6 |
7 | class GraphStateHook(HookProvider):
8 |
9 | def register_hooks(self, registry: HookRegistry, **kwargs: Any) -> None: # type: ignore
10 | registry.add_callback(BeforeNodeCallEvent, self.before_node_call)
11 | registry.add_callback(AfterNodeCallEvent, self.after_node_call)
12 |
13 | @staticmethod
14 | def before_node_call(event: BeforeNodeCallEvent):
15 | event.invocation_state.update({
16 | "source_graph": event.source
17 | })
18 |
19 | @staticmethod
20 | def after_node_call(event: AfterNodeCallEvent):
21 | event.invocation_state.pop("source_graph", None)
22 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/circle-clock-loader-375.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-arrow-up.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/position-top-t.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/screen-swith-full.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/drawer-control-l.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/drawer-control-r.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-arrow-down.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-arrow-left.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/position-top-b.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/hatchify/core/graph/tools/math_tool.py:
--------------------------------------------------------------------------------
1 | """Math tools for arithmetic operations.
2 |
3 | Demonstrates:
4 | 1. How to get tool's input schema as Pydantic Model for Agent structured_output
5 | 2. How to auto-generate output schema from tool's return transport
6 | """
7 |
8 | from strands import tool
9 | from strands.tools.decorator import DecoratedFunctionTool
10 |
11 | from hatchify.core.factory.tool_factory import ToolRouter
12 |
13 | # math_router 只包含 @tool 装饰的函数
14 | math_router = ToolRouter[DecoratedFunctionTool]()
15 |
16 |
17 | @tool(name="add", description="Add two numbers")
18 | async def add(a: float, b: float) -> float:
19 | """Add two numbers together.
20 |
21 | Args:
22 | a: First number
23 | b: Second number
24 |
25 | Returns:
26 | Sum of a and b
27 | """
28 | return a + b
29 |
30 |
31 | math_router.register(add)
32 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/screen-swith-collapse.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/trends.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/zoom-out.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/avatar-filled.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/right-muti.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/web/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 | "target": "ES2022",
5 | "useDefineForClassFields": true,
6 | "lib": ["ES2022", "DOM", "DOM.Iterable"],
7 | "module": "ESNext",
8 | "types": ["vite/client"],
9 | "skipLibCheck": true,
10 |
11 | /* Bundler mode */
12 | "moduleResolution": "bundler",
13 | "allowImportingTsExtensions": true,
14 | "verbatimModuleSyntax": true,
15 | "moduleDetection": "force",
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 |
19 | /* Linting */
20 | "strict": true,
21 | "noUnusedLocals": false,
22 | "noUnusedParameters": false,
23 | "erasableSyntaxOnly": true,
24 | "noFallthroughCasesInSwitch": true,
25 | "noUncheckedSideEffectImports": true,
26 | "paths": {
27 | "@/*": ["./src/*"]
28 | }
29 | },
30 | "include": ["src"]
31 | }
32 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/clock-loader-50.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/currency-yuan.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/sort-normal.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/trending-down.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-double-outline-l-l.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/line-chart-4.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/trending-up.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-double-outline-l-r.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-double-outline-m-b.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/web/packages/icons/icons/arrow-double-outline-s-b.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------