mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-17 10:12:02 -05:00
Compare commits
1 Commits
dev
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c297d7d871 |
@@ -104,8 +104,8 @@ def _get_linear_config() -> tuple[LinearClient, str, str]:
|
||||
Raises RuntimeError if any required setting is missing.
|
||||
"""
|
||||
secrets = _get_settings().secrets
|
||||
if not secrets.copilot_linear_api_key:
|
||||
raise RuntimeError("COPILOT_LINEAR_API_KEY is not configured")
|
||||
if not secrets.linear_api_key:
|
||||
raise RuntimeError("LINEAR_API_KEY is not configured")
|
||||
if not secrets.linear_feature_request_project_id:
|
||||
raise RuntimeError("LINEAR_FEATURE_REQUEST_PROJECT_ID is not configured")
|
||||
if not secrets.linear_feature_request_team_id:
|
||||
@@ -114,7 +114,7 @@ def _get_linear_config() -> tuple[LinearClient, str, str]:
|
||||
credentials = APIKeyCredentials(
|
||||
id="system-linear",
|
||||
provider="linear",
|
||||
api_key=SecretStr(secrets.copilot_linear_api_key),
|
||||
api_key=SecretStr(secrets.linear_api_key),
|
||||
title="System Linear API Key",
|
||||
)
|
||||
client = LinearClient(credentials=credentials)
|
||||
|
||||
@@ -662,7 +662,7 @@ class Secrets(UpdateTrackingModel["Secrets"], BaseSettings):
|
||||
mem0_api_key: str = Field(default="", description="Mem0 API key")
|
||||
elevenlabs_api_key: str = Field(default="", description="ElevenLabs API key")
|
||||
|
||||
copilot_linear_api_key: str = Field(
|
||||
linear_api_key: str = Field(
|
||||
default="", description="Linear API key for system-level operations"
|
||||
)
|
||||
linear_feature_request_project_id: str = Field(
|
||||
|
||||
53
autogpt_platform/backend/poetry.lock
generated
53
autogpt_platform/backend/poetry.lock
generated
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aio-pika"
|
||||
@@ -374,7 +374,7 @@ description = "LTS Port of Python audioop"
|
||||
optional = false
|
||||
python-versions = ">=3.13"
|
||||
groups = ["main"]
|
||||
markers = "python_version >= \"3.13\""
|
||||
markers = "python_version == \"3.13\""
|
||||
files = [
|
||||
{file = "audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800"},
|
||||
{file = "audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303"},
|
||||
@@ -474,7 +474,7 @@ description = "Backport of asyncio.Runner, a context manager that controls event
|
||||
optional = false
|
||||
python-versions = "<3.11,>=3.8"
|
||||
groups = ["main"]
|
||||
markers = "python_version < \"3.11\""
|
||||
markers = "python_version == \"3.10\""
|
||||
files = [
|
||||
{file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"},
|
||||
{file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"},
|
||||
@@ -487,7 +487,7 @@ description = "Backport of CPython tarfile module"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
markers = "python_version <= \"3.11\""
|
||||
markers = "python_version < \"3.12\""
|
||||
files = [
|
||||
{file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"},
|
||||
{file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"},
|
||||
@@ -659,7 +659,6 @@ description = "Foreign Function Interface for Python calling C code."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
markers = "platform_python_implementation != \"PyPy\" or sys_platform == \"darwin\""
|
||||
files = [
|
||||
{file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"},
|
||||
{file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"},
|
||||
@@ -1361,7 +1360,7 @@ description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main", "dev"]
|
||||
markers = "python_version < \"3.11\""
|
||||
markers = "python_version == \"3.10\""
|
||||
files = [
|
||||
{file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"},
|
||||
{file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"},
|
||||
@@ -1390,18 +1389,21 @@ tests = ["coverage", "coveralls", "dill", "mock", "nose"]
|
||||
|
||||
[[package]]
|
||||
name = "faker"
|
||||
version = "38.3.0"
|
||||
version = "40.4.0"
|
||||
description = "Faker is a Python package that generates fake data for you."
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "faker-38.3.0-py3-none-any.whl", hash = "sha256:b5499b6f2d090dec9b90ded8eae6a27daed10fda3e0dba7a182bb2be8a4d4a6b"},
|
||||
{file = "faker-38.3.0.tar.gz", hash = "sha256:4997de214510db9328ed83b9591891c66e91d7e9a903e5744e0255a68f51ac16"},
|
||||
{file = "faker-40.4.0-py3-none-any.whl", hash = "sha256:486d43c67ebbb136bc932406418744f9a0bdf2c07f77703ea78b58b77e9aa443"},
|
||||
{file = "faker-40.4.0.tar.gz", hash = "sha256:76f8e74a3df28c3e2ec2caafa956e19e37a132fdc7ea067bc41783affcfee364"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tzdata = "*"
|
||||
tzdata = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[package.extras]
|
||||
tzdata = ["tzdata"]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
@@ -1843,16 +1845,16 @@ files = [
|
||||
google-auth = ">=2.14.1,<3.0.0"
|
||||
googleapis-common-protos = ">=1.56.2,<2.0.0"
|
||||
grpcio = [
|
||||
{version = ">=1.33.2,<2.0.0", optional = true, markers = "extra == \"grpc\""},
|
||||
{version = ">=1.49.1,<2.0.0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""},
|
||||
{version = ">=1.33.2,<2.0.0", optional = true, markers = "extra == \"grpc\""},
|
||||
]
|
||||
grpcio-status = [
|
||||
{version = ">=1.33.2,<2.0.0", optional = true, markers = "extra == \"grpc\""},
|
||||
{version = ">=1.49.1,<2.0.0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""},
|
||||
{version = ">=1.33.2,<2.0.0", optional = true, markers = "extra == \"grpc\""},
|
||||
]
|
||||
proto-plus = [
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
{version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
]
|
||||
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
|
||||
requests = ">=2.18.0,<3.0.0"
|
||||
@@ -1963,8 +1965,8 @@ google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0", extras
|
||||
google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0"
|
||||
grpcio = ">=1.33.2,<2.0.0"
|
||||
proto-plus = [
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
{version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
]
|
||||
protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
|
||||
|
||||
@@ -2024,9 +2026,9 @@ google-cloud-core = ">=2.0.0,<3.0.0"
|
||||
grpc-google-iam-v1 = ">=0.12.4,<1.0.0"
|
||||
opentelemetry-api = ">=1.9.0"
|
||||
proto-plus = [
|
||||
{version = ">=1.22.0,<2.0.0"},
|
||||
{version = ">=1.22.2,<2.0.0", markers = "python_version >= \"3.11\""},
|
||||
{version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
{version = ">=1.22.2,<2.0.0", markers = "python_version >= \"3.11\" and python_version < \"3.13\""},
|
||||
{version = ">=1.22.0,<2.0.0", markers = "python_version < \"3.11\""},
|
||||
]
|
||||
protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
|
||||
|
||||
@@ -3870,7 +3872,7 @@ description = "Fundamental package for array computing in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
markers = "python_version < \"3.11\""
|
||||
markers = "python_version == \"3.10\""
|
||||
files = [
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"},
|
||||
@@ -4355,9 +4357,9 @@ files = [
|
||||
|
||||
[package.dependencies]
|
||||
numpy = [
|
||||
{version = ">=1.22.4", markers = "python_version < \"3.11\""},
|
||||
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
||||
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
||||
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
||||
{version = ">=1.22.4", markers = "python_version < \"3.11\""},
|
||||
]
|
||||
python-dateutil = ">=2.8.2"
|
||||
pytz = ">=2020.1"
|
||||
@@ -4600,8 +4602,8 @@ pinecone-plugin-interface = ">=0.0.7,<0.0.8"
|
||||
python-dateutil = ">=2.5.3"
|
||||
typing-extensions = ">=3.7.4"
|
||||
urllib3 = [
|
||||
{version = ">=1.26.0", markers = "python_version >= \"3.8\" and python_version < \"3.12\""},
|
||||
{version = ">=1.26.5", markers = "python_version >= \"3.12\" and python_version < \"4.0\""},
|
||||
{version = ">=1.26.0", markers = "python_version >= \"3.8\" and python_version < \"3.12\""},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@@ -5429,7 +5431,7 @@ description = "C parser in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
markers = "(platform_python_implementation != \"PyPy\" or sys_platform == \"darwin\") and implementation_name != \"PyPy\""
|
||||
markers = "implementation_name != \"PyPy\""
|
||||
files = [
|
||||
{file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"},
|
||||
{file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"},
|
||||
@@ -6198,10 +6200,10 @@ files = [
|
||||
grpcio = ">=1.41.0"
|
||||
httpx = {version = ">=0.20.0", extras = ["http2"]}
|
||||
numpy = [
|
||||
{version = ">=1.21,<2.3.0", markers = "python_version == \"3.10\""},
|
||||
{version = ">=1.21", markers = "python_version == \"3.11\""},
|
||||
{version = ">=2.1.0", markers = "python_version == \"3.13\""},
|
||||
{version = ">=1.21", markers = "python_version == \"3.11\""},
|
||||
{version = ">=1.26", markers = "python_version == \"3.12\""},
|
||||
{version = ">=1.21,<2.3.0", markers = "python_version == \"3.10\""},
|
||||
]
|
||||
portalocker = ">=2.7.0,<4.0"
|
||||
protobuf = ">=3.20.0"
|
||||
@@ -7407,7 +7409,7 @@ description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main", "dev"]
|
||||
markers = "python_version < \"3.11\""
|
||||
markers = "python_version == \"3.10\""
|
||||
files = [
|
||||
{file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"},
|
||||
{file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"},
|
||||
@@ -7583,6 +7585,7 @@ files = [
|
||||
{file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"},
|
||||
{file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"},
|
||||
]
|
||||
markers = {dev = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "tzlocal"
|
||||
@@ -8530,4 +8533,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.10,<3.14"
|
||||
content-hash = "55e095de555482f0fe47de7695f390fe93e7bcf739b31c391b2e5e3c3d938ae3"
|
||||
content-hash = "73d5ca72e97dce394fe111708cb5be0c714f9812b016de45ad0b84de85a833bc"
|
||||
|
||||
@@ -93,7 +93,7 @@ posthog = "^7.6.0"
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
aiohappyeyeballs = "^2.6.1"
|
||||
black = "^24.10.0"
|
||||
faker = "^38.2.0"
|
||||
faker = "^40.4.0"
|
||||
httpx = "^0.28.1"
|
||||
isort = "^5.13.2"
|
||||
poethepoet = "^0.41.0"
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
"@rjsf/validator-ajv8": "6.1.2",
|
||||
"@sentry/nextjs": "10.27.0",
|
||||
"@streamdown/cjk": "1.0.1",
|
||||
"@streamdown/code": "1.0.1",
|
||||
"@streamdown/math": "1.0.1",
|
||||
"@streamdown/mermaid": "1.0.1",
|
||||
"@supabase/ssr": "0.7.0",
|
||||
@@ -115,7 +116,6 @@
|
||||
"remark-gfm": "4.0.1",
|
||||
"remark-math": "6.0.0",
|
||||
"shepherd.js": "14.5.1",
|
||||
"shiki": "^3.21.0",
|
||||
"sonner": "2.0.7",
|
||||
"streamdown": "2.1.0",
|
||||
"tailwind-merge": "2.6.0",
|
||||
|
||||
16
autogpt_platform/frontend/pnpm-lock.yaml
generated
16
autogpt_platform/frontend/pnpm-lock.yaml
generated
@@ -108,6 +108,9 @@ importers:
|
||||
'@streamdown/cjk':
|
||||
specifier: 1.0.1
|
||||
version: 1.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(react@18.3.1)(unified@11.0.5)
|
||||
'@streamdown/code':
|
||||
specifier: 1.0.1
|
||||
version: 1.0.1(react@18.3.1)
|
||||
'@streamdown/math':
|
||||
specifier: 1.0.1
|
||||
version: 1.0.1(react@18.3.1)
|
||||
@@ -267,9 +270,6 @@ importers:
|
||||
shepherd.js:
|
||||
specifier: 14.5.1
|
||||
version: 14.5.1
|
||||
shiki:
|
||||
specifier: ^3.21.0
|
||||
version: 3.21.0
|
||||
sonner:
|
||||
specifier: 2.0.7
|
||||
version: 2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -3307,6 +3307,11 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
|
||||
'@streamdown/code@1.0.1':
|
||||
resolution: {integrity: sha512-U9LITfQ28tZYAoY922jdtw1ryg4kgRBdURopqK9hph7G2fBUwPeHthjH7SvaV0fvFv7EqjqCzARJuWUljLe9Ag==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
|
||||
'@streamdown/math@1.0.1':
|
||||
resolution: {integrity: sha512-R9WdHbpERiRU7WeO7oT1aIbnLJ/jraDr89F7X9x2OM//Y8G8UMATRnLD/RUwg4VLr8Nu7QSIJ0Pa8lXd2meM4Q==}
|
||||
peerDependencies:
|
||||
@@ -11902,6 +11907,11 @@ snapshots:
|
||||
- micromark-util-types
|
||||
- unified
|
||||
|
||||
'@streamdown/code@1.0.1(react@18.3.1)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
shiki: 3.21.0
|
||||
|
||||
'@streamdown/math@1.0.1(react@18.3.1)':
|
||||
dependencies:
|
||||
katex: 0.16.28
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/molecules/DropdownMenu/DropdownMenu";
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { DotsThree } from "@phosphor-icons/react";
|
||||
// TODO: Replace with modern Dialog component when available
|
||||
import DeleteConfirmDialog from "@/components/__legacy__/delete-confirm-dialog";
|
||||
import { ChatContainer } from "./components/ChatContainer/ChatContainer";
|
||||
import { ChatSidebar } from "./components/ChatSidebar/ChatSidebar";
|
||||
import { DeleteChatDialog } from "./components/DeleteChatDialog/DeleteChatDialog";
|
||||
import { MobileDrawer } from "./components/MobileDrawer/MobileDrawer";
|
||||
import { MobileHeader } from "./components/MobileHeader/MobileHeader";
|
||||
import { ScaleLoader } from "./components/ScaleLoader/ScaleLoader";
|
||||
@@ -62,7 +56,19 @@ export function CopilotPage() {
|
||||
>
|
||||
{!isMobile && <ChatSidebar />}
|
||||
<div className="relative flex h-full w-full flex-col overflow-hidden bg-[#f8f8f9] px-0">
|
||||
{isMobile && <MobileHeader onOpenDrawer={handleOpenDrawer} />}
|
||||
{isMobile && (
|
||||
<MobileHeader
|
||||
onOpenDrawer={handleOpenDrawer}
|
||||
showDelete={!!sessionId}
|
||||
isDeleting={isDeleting}
|
||||
onDelete={() => {
|
||||
const session = sessions.find((s) => s.id === sessionId);
|
||||
if (session) {
|
||||
handleDeleteClick(session.id, session.title);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<ChatContainer
|
||||
messages={messages}
|
||||
@@ -74,38 +80,6 @@ export function CopilotPage() {
|
||||
onCreateSession={createSession}
|
||||
onSend={onSend}
|
||||
onStop={stop}
|
||||
headerSlot={
|
||||
isMobile && sessionId ? (
|
||||
<div className="flex justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
className="rounded p-1.5 hover:bg-neutral-100"
|
||||
aria-label="More actions"
|
||||
>
|
||||
<DotsThree className="h-5 w-5 text-neutral-600" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
const session = sessions.find(
|
||||
(s) => s.id === sessionId,
|
||||
);
|
||||
if (session) {
|
||||
handleDeleteClick(session.id, session.title);
|
||||
}
|
||||
}}
|
||||
disabled={isDeleting}
|
||||
className="text-red-600 focus:bg-red-50 focus:text-red-600"
|
||||
>
|
||||
Delete chat
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -123,11 +97,12 @@ export function CopilotPage() {
|
||||
)}
|
||||
{/* Delete confirmation dialog - rendered at top level for proper z-index on mobile */}
|
||||
{isMobile && (
|
||||
<DeleteChatDialog
|
||||
session={sessionToDelete}
|
||||
isDeleting={isDeleting}
|
||||
onConfirm={handleConfirmDelete}
|
||||
onCancel={handleCancelDelete}
|
||||
<DeleteConfirmDialog
|
||||
entityType="chat"
|
||||
entityName={sessionToDelete?.title || "Untitled chat"}
|
||||
open={!!sessionToDelete}
|
||||
onOpenChange={(open) => !open && handleCancelDelete()}
|
||||
onDoDelete={handleConfirmDelete}
|
||||
/>
|
||||
)}
|
||||
</SidebarProvider>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { ChatInput } from "@/app/(platform)/copilot/components/ChatInput/ChatInput";
|
||||
import { UIDataTypes, UIMessage, UITools } from "ai";
|
||||
import { LayoutGroup, motion } from "framer-motion";
|
||||
import { ReactNode } from "react";
|
||||
import { ChatMessagesContainer } from "../ChatMessagesContainer/ChatMessagesContainer";
|
||||
import { CopilotChatActionsProvider } from "../CopilotChatActionsProvider/CopilotChatActionsProvider";
|
||||
import { EmptySession } from "../EmptySession/EmptySession";
|
||||
@@ -17,7 +16,6 @@ export interface ChatContainerProps {
|
||||
onCreateSession: () => void | Promise<string>;
|
||||
onSend: (message: string) => void | Promise<void>;
|
||||
onStop: () => void;
|
||||
headerSlot?: ReactNode;
|
||||
}
|
||||
export const ChatContainer = ({
|
||||
messages,
|
||||
@@ -29,7 +27,6 @@ export const ChatContainer = ({
|
||||
onCreateSession,
|
||||
onSend,
|
||||
onStop,
|
||||
headerSlot,
|
||||
}: ChatContainerProps) => {
|
||||
const inputLayoutId = "copilot-2-chat-input";
|
||||
|
||||
@@ -44,7 +41,6 @@ export const ChatContainer = ({
|
||||
status={status}
|
||||
error={error}
|
||||
isLoading={isLoadingSession}
|
||||
headerSlot={headerSlot}
|
||||
/>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
|
||||
@@ -118,7 +118,6 @@ interface ChatMessagesContainerProps {
|
||||
status: string;
|
||||
error: Error | undefined;
|
||||
isLoading: boolean;
|
||||
headerSlot?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const ChatMessagesContainer = ({
|
||||
@@ -126,7 +125,6 @@ export const ChatMessagesContainer = ({
|
||||
status,
|
||||
error,
|
||||
isLoading,
|
||||
headerSlot,
|
||||
}: ChatMessagesContainerProps) => {
|
||||
const [thinkingPhrase, setThinkingPhrase] = useState(getRandomPhrase);
|
||||
const lastToastTimeRef = useRef(0);
|
||||
@@ -167,7 +165,6 @@ export const ChatMessagesContainer = ({
|
||||
return (
|
||||
<Conversation className="min-h-0 flex-1">
|
||||
<ConversationContent className="flex flex-1 flex-col gap-6 px-3 py-6">
|
||||
{headerSlot}
|
||||
{isLoading && messages.length === 0 && (
|
||||
<div className="flex min-h-full flex-1 items-center justify-center">
|
||||
<LoadingSpinner className="text-neutral-600" />
|
||||
|
||||
@@ -7,13 +7,9 @@ import {
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/molecules/DropdownMenu/DropdownMenu";
|
||||
import { toast } from "@/components/molecules/Toast/use-toast";
|
||||
// TODO: Replace with modern Dialog component when available
|
||||
import DeleteConfirmDialog from "@/components/__legacy__/delete-confirm-dialog";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -23,12 +19,11 @@ import {
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { DotsThree, PlusCircleIcon, PlusIcon } from "@phosphor-icons/react";
|
||||
import { PlusCircleIcon, PlusIcon, TrashIcon } from "@phosphor-icons/react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { motion } from "framer-motion";
|
||||
import { parseAsString, useQueryState } from "nuqs";
|
||||
import { useState } from "react";
|
||||
import { DeleteChatDialog } from "../DeleteChatDialog/DeleteChatDialog";
|
||||
import { parseAsString, useQueryState } from "nuqs";
|
||||
|
||||
export function ChatSidebar() {
|
||||
const { state } = useSidebar();
|
||||
@@ -97,12 +92,6 @@ export function ChatSidebar() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancelDelete() {
|
||||
if (!isDeleting) {
|
||||
setSessionToDelete(null);
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(dateString: string) {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
@@ -231,28 +220,16 @@ export function ChatSidebar() {
|
||||
</Text>
|
||||
</div>
|
||||
</button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-zinc-600 transition-all hover:bg-neutral-100"
|
||||
aria-label="More actions"
|
||||
>
|
||||
<DotsThree className="h-4 w-4" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={(e) =>
|
||||
handleDeleteClick(e, session.id, session.title)
|
||||
}
|
||||
disabled={isDeleting}
|
||||
className="text-red-600 focus:bg-red-50 focus:text-red-600"
|
||||
>
|
||||
Delete chat
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<button
|
||||
onClick={(e) =>
|
||||
handleDeleteClick(e, session.id, session.title)
|
||||
}
|
||||
disabled={isDeleting}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 rounded p-1.5 text-zinc-400 opacity-0 transition-all group-hover:opacity-100 hover:bg-red-100 hover:text-red-600 focus-visible:opacity-100 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
aria-label="Delete chat"
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
@@ -280,11 +257,12 @@ export function ChatSidebar() {
|
||||
)}
|
||||
</Sidebar>
|
||||
|
||||
<DeleteChatDialog
|
||||
session={sessionToDelete}
|
||||
isDeleting={isDeleting}
|
||||
onConfirm={handleConfirmDelete}
|
||||
onCancel={handleCancelDelete}
|
||||
<DeleteConfirmDialog
|
||||
entityType="chat"
|
||||
entityName={sessionToDelete?.title || "Untitled chat"}
|
||||
open={!!sessionToDelete}
|
||||
onOpenChange={(open) => !open && setSessionToDelete(null)}
|
||||
onDoDelete={handleConfirmDelete}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import { Dialog } from "@/components/molecules/Dialog/Dialog";
|
||||
|
||||
interface Props {
|
||||
session: { id: string; title: string | null | undefined } | null;
|
||||
isDeleting: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export function DeleteChatDialog({
|
||||
session,
|
||||
isDeleting,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
}: Props) {
|
||||
return (
|
||||
<Dialog
|
||||
title="Delete chat"
|
||||
styling={{ maxWidth: "30rem", minWidth: "auto" }}
|
||||
controlled={{
|
||||
isOpen: !!session,
|
||||
set: async (open) => {
|
||||
if (!open && !isDeleting) {
|
||||
onCancel();
|
||||
}
|
||||
},
|
||||
}}
|
||||
onClose={isDeleting ? undefined : onCancel}
|
||||
>
|
||||
<Dialog.Content>
|
||||
<Text variant="body">
|
||||
Are you sure you want to delete{" "}
|
||||
<Text variant="body-medium" as="span">
|
||||
"{session?.title || "Untitled chat"}"
|
||||
</Text>
|
||||
? This action cannot be undone.
|
||||
</Text>
|
||||
<Dialog.Footer>
|
||||
<Button variant="secondary" onClick={onCancel} disabled={isDeleting}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={onConfirm}
|
||||
loading={isDeleting}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { NAVBAR_HEIGHT_PX } from "@/lib/constants";
|
||||
import { ListIcon } from "@phosphor-icons/react";
|
||||
import { ListIcon, TrashIcon } from "@phosphor-icons/react";
|
||||
|
||||
interface Props {
|
||||
onOpenDrawer: () => void;
|
||||
showDelete?: boolean;
|
||||
isDeleting?: boolean;
|
||||
onDelete?: () => void;
|
||||
}
|
||||
|
||||
export function MobileHeader({ onOpenDrawer }: Props) {
|
||||
export function MobileHeader({
|
||||
onOpenDrawer,
|
||||
showDelete,
|
||||
isDeleting,
|
||||
onDelete,
|
||||
}: Props) {
|
||||
return (
|
||||
<div
|
||||
className="fixed z-50 flex gap-2"
|
||||
@@ -21,6 +29,18 @@ export function MobileHeader({ onOpenDrawer }: Props) {
|
||||
>
|
||||
<ListIcon width="1.25rem" height="1.25rem" />
|
||||
</Button>
|
||||
{showDelete && onDelete && (
|
||||
<Button
|
||||
variant="icon"
|
||||
size="icon"
|
||||
aria-label="Delete current chat"
|
||||
onClick={onDelete}
|
||||
disabled={isDeleting}
|
||||
className="bg-white text-red-500 shadow-md hover:bg-red-50 hover:text-red-600 disabled:opacity-50"
|
||||
>
|
||||
<TrashIcon width="1.25rem" height="1.25rem" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -192,10 +192,8 @@ export function useCopilotPage() {
|
||||
}, [sessionToDelete, deleteSessionMutation]);
|
||||
|
||||
const handleCancelDelete = useCallback(() => {
|
||||
if (!isDeleting) {
|
||||
setSessionToDelete(null);
|
||||
}
|
||||
}, [isDeleting]);
|
||||
setSessionToDelete(null);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
sessionId,
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cjk } from "@streamdown/cjk";
|
||||
import { code } from "@/lib/streamdown-code-plugin";
|
||||
import { code } from "@streamdown/code";
|
||||
import { math } from "@streamdown/math";
|
||||
import { mermaid } from "@streamdown/mermaid";
|
||||
import type { UIMessage } from "ai";
|
||||
|
||||
@@ -25,7 +25,7 @@ export function BaseFooter({
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={`flex w-full items-end justify-end gap-4 pt-6 ${className}`}
|
||||
className={`flex w-full items-end justify-between gap-4 pt-6 ${className}`}
|
||||
data-testid={testId}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import {
|
||||
bundledLanguages,
|
||||
bundledLanguagesInfo,
|
||||
createHighlighter,
|
||||
type BundledLanguage,
|
||||
type BundledTheme,
|
||||
type HighlighterGeneric,
|
||||
} from "shiki";
|
||||
|
||||
export type { BundledLanguage, BundledTheme };
|
||||
|
||||
const LANGUAGE_ALIASES: Record<string, string> = Object.fromEntries(
|
||||
bundledLanguagesInfo.flatMap((lang) =>
|
||||
(lang.aliases ?? []).map((alias) => [alias, lang.id]),
|
||||
),
|
||||
);
|
||||
|
||||
const SUPPORTED_LANGUAGES = new Set(Object.keys(bundledLanguages));
|
||||
|
||||
const PRELOAD_LANGUAGES: BundledLanguage[] = [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"python",
|
||||
"json",
|
||||
"bash",
|
||||
"yaml",
|
||||
"markdown",
|
||||
"html",
|
||||
"css",
|
||||
"sql",
|
||||
"tsx",
|
||||
"jsx",
|
||||
];
|
||||
|
||||
export const SHIKI_THEMES: [BundledTheme, BundledTheme] = [
|
||||
"github-light",
|
||||
"github-dark",
|
||||
];
|
||||
|
||||
let highlighterPromise: Promise<
|
||||
HighlighterGeneric<BundledLanguage, BundledTheme>
|
||||
> | null = null;
|
||||
|
||||
export function getShikiHighlighter(): Promise<
|
||||
HighlighterGeneric<BundledLanguage, BundledTheme>
|
||||
> {
|
||||
if (!highlighterPromise) {
|
||||
highlighterPromise = createHighlighter({
|
||||
themes: SHIKI_THEMES,
|
||||
langs: PRELOAD_LANGUAGES,
|
||||
}).catch((err) => {
|
||||
highlighterPromise = null;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
return highlighterPromise;
|
||||
}
|
||||
|
||||
export function resolveLanguage(lang: string): string {
|
||||
const normalized = lang.trim().toLowerCase();
|
||||
return LANGUAGE_ALIASES[normalized] ?? normalized;
|
||||
}
|
||||
|
||||
export function isLanguageSupported(lang: string): boolean {
|
||||
return SUPPORTED_LANGUAGES.has(resolveLanguage(lang));
|
||||
}
|
||||
|
||||
export function getSupportedLanguages(): BundledLanguage[] {
|
||||
return Array.from(SUPPORTED_LANGUAGES) as BundledLanguage[];
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
import type { CodeHighlighterPlugin } from "streamdown";
|
||||
|
||||
import {
|
||||
type BundledLanguage,
|
||||
type BundledTheme,
|
||||
getShikiHighlighter,
|
||||
getSupportedLanguages,
|
||||
isLanguageSupported,
|
||||
resolveLanguage,
|
||||
SHIKI_THEMES,
|
||||
} from "./shiki-highlighter";
|
||||
|
||||
interface HighlightResult {
|
||||
tokens: {
|
||||
content: string;
|
||||
color?: string;
|
||||
htmlStyle?: Record<string, string>;
|
||||
}[][];
|
||||
fg?: string;
|
||||
bg?: string;
|
||||
}
|
||||
|
||||
type HighlightCallback = (result: HighlightResult) => void;
|
||||
|
||||
const MAX_CACHE_SIZE = 500;
|
||||
const tokenCache = new Map<string, HighlightResult>();
|
||||
const pendingCallbacks = new Map<string, Set<HighlightCallback>>();
|
||||
const inFlightLanguageLoads = new Map<string, Promise<void>>();
|
||||
|
||||
function simpleHash(str: string): string {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = (hash << 5) - hash + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
return hash.toString(36);
|
||||
}
|
||||
|
||||
function getCacheKey(
|
||||
code: string,
|
||||
lang: string,
|
||||
themes: readonly string[],
|
||||
): string {
|
||||
return `${lang}:${themes.join(",")}:${simpleHash(code)}`;
|
||||
}
|
||||
|
||||
function evictOldestIfNeeded(): void {
|
||||
if (tokenCache.size > MAX_CACHE_SIZE) {
|
||||
const oldestKey = tokenCache.keys().next().value;
|
||||
if (oldestKey) {
|
||||
tokenCache.delete(oldestKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createSingletonCodePlugin(): CodeHighlighterPlugin {
|
||||
return {
|
||||
name: "shiki",
|
||||
type: "code-highlighter",
|
||||
|
||||
supportsLanguage(lang: BundledLanguage): boolean {
|
||||
return isLanguageSupported(lang);
|
||||
},
|
||||
|
||||
getSupportedLanguages(): BundledLanguage[] {
|
||||
return getSupportedLanguages();
|
||||
},
|
||||
|
||||
getThemes(): [BundledTheme, BundledTheme] {
|
||||
return SHIKI_THEMES;
|
||||
},
|
||||
|
||||
highlight({ code, language, themes }, callback) {
|
||||
const lang = resolveLanguage(language);
|
||||
const cacheKey = getCacheKey(code, lang, themes);
|
||||
|
||||
if (tokenCache.has(cacheKey)) {
|
||||
return tokenCache.get(cacheKey)!;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
if (!pendingCallbacks.has(cacheKey)) {
|
||||
pendingCallbacks.set(cacheKey, new Set());
|
||||
}
|
||||
pendingCallbacks.get(cacheKey)!.add(callback);
|
||||
}
|
||||
|
||||
getShikiHighlighter()
|
||||
.then(async (highlighter) => {
|
||||
const loadedLanguages = highlighter.getLoadedLanguages();
|
||||
|
||||
if (!loadedLanguages.includes(lang) && isLanguageSupported(lang)) {
|
||||
let loadPromise = inFlightLanguageLoads.get(lang);
|
||||
if (!loadPromise) {
|
||||
loadPromise = highlighter
|
||||
.loadLanguage(lang as BundledLanguage)
|
||||
.finally(() => {
|
||||
inFlightLanguageLoads.delete(lang);
|
||||
});
|
||||
inFlightLanguageLoads.set(lang, loadPromise);
|
||||
}
|
||||
await loadPromise;
|
||||
}
|
||||
|
||||
const finalLang = (
|
||||
highlighter.getLoadedLanguages().includes(lang) ? lang : "text"
|
||||
) as BundledLanguage;
|
||||
|
||||
const shikiResult = highlighter.codeToTokens(code, {
|
||||
lang: finalLang,
|
||||
themes: { light: themes[0], dark: themes[1] },
|
||||
});
|
||||
|
||||
const result: HighlightResult = {
|
||||
tokens: shikiResult.tokens.map((line) =>
|
||||
line.map((token) => ({
|
||||
content: token.content,
|
||||
color: token.color,
|
||||
htmlStyle: token.htmlStyle,
|
||||
})),
|
||||
),
|
||||
fg: shikiResult.fg,
|
||||
bg: shikiResult.bg,
|
||||
};
|
||||
|
||||
evictOldestIfNeeded();
|
||||
tokenCache.set(cacheKey, result);
|
||||
|
||||
const callbacks = pendingCallbacks.get(cacheKey);
|
||||
if (callbacks) {
|
||||
callbacks.forEach((cb) => {
|
||||
cb(result);
|
||||
});
|
||||
pendingCallbacks.delete(cacheKey);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("[Shiki] Failed to highlight code:", error);
|
||||
|
||||
const fallback: HighlightResult = {
|
||||
tokens: code.split("\n").map((line) => [{ content: line }]),
|
||||
};
|
||||
|
||||
const callbacks = pendingCallbacks.get(cacheKey);
|
||||
if (callbacks) {
|
||||
callbacks.forEach((cb) => {
|
||||
cb(fallback);
|
||||
});
|
||||
pendingCallbacks.delete(cacheKey);
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const code = createSingletonCodePlugin();
|
||||
@@ -465,13 +465,9 @@ export async function navigateToAgentByName(
|
||||
export async function clickRunButton(page: Page): Promise<void> {
|
||||
const { getId } = getSelectors(page);
|
||||
|
||||
// Wait for sidebar loading to complete before detecting buttons.
|
||||
// During sidebar loading, the "New task" button appears transiently
|
||||
// even for agents with no items, then switches to "Setup your task"
|
||||
// once loading finishes. Waiting for network idle ensures the page
|
||||
// has settled into its final state.
|
||||
await page.waitForLoadState("networkidle");
|
||||
|
||||
// Wait for page to stabilize and buttons to render
|
||||
// The NewAgentLibraryView shows either "Setup your task" (empty state)
|
||||
// or "New task" (with items) button
|
||||
const setupTaskButton = page.getByRole("button", {
|
||||
name: /Setup your task/i,
|
||||
});
|
||||
@@ -479,7 +475,8 @@ export async function clickRunButton(page: Page): Promise<void> {
|
||||
const runButton = getId("agent-run-button");
|
||||
const runAgainButton = getId("run-again-button");
|
||||
|
||||
// Wait for any of the buttons to appear
|
||||
// Use Promise.race with waitFor to wait for any of the buttons to appear
|
||||
// This handles the async rendering in CI environments
|
||||
try {
|
||||
await Promise.race([
|
||||
setupTaskButton.waitFor({ state: "visible", timeout: 15000 }),
|
||||
@@ -493,7 +490,7 @@ export async function clickRunButton(page: Page): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
// Check which button is visible and click it
|
||||
// Now check which button is visible and click it
|
||||
if (await setupTaskButton.isVisible()) {
|
||||
await setupTaskButton.click();
|
||||
const startTaskButton = page
|
||||
@@ -537,9 +534,7 @@ export async function runAgent(page: Page): Promise<void> {
|
||||
|
||||
export async function waitForAgentPageLoad(page: Page): Promise<void> {
|
||||
await page.waitForURL(/.*\/library\/agents\/[^/]+/);
|
||||
// Wait for sidebar data to finish loading so the page settles
|
||||
// into its final state (empty view vs sidebar view)
|
||||
await page.waitForLoadState("networkidle");
|
||||
await page.getByTestId("Run actions").isVisible({ timeout: 10000 });
|
||||
}
|
||||
|
||||
export async function getAgentName(page: Page): Promise<string> {
|
||||
|
||||
Reference in New Issue
Block a user