Compare commits

...

2 Commits

Author SHA1 Message Date
ZhenYi
9336250f1c fix(agent): skip reasoning_effort when think=false to avoid API errors
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-18 19:41:59 +08:00
ZhenYi
168f14fbac chore: remove .next build artifacts from tracking 2026-04-18 19:33:42 +08:00
18 changed files with 43 additions and 539 deletions

3
.gitignore vendored
View File

@ -15,4 +15,5 @@ deploy/secrets.yaml
AGENT.md
ARCHITECTURE.md
.agents
.agents.md
.agents.md
.next

View File

@ -1 +0,0 @@
{"previewModeId":"ce3f288bfc676d22dc4c8451698f43ff","previewModeSigningKey":"07f92b6308a6126f36d71e78252c52e029f15d27f2d9eb156ebeba1b7c17b831","previewModeEncryptionKey":"efdc9600f7d4bcef633ac1e3be3348b32564789ea4916ea5adafb5b512cbe456","expireAt":1777702293556}

View File

@ -1 +0,0 @@
{"encryption.key":"Hqnv4g8ZhwVTYVrYYvM4IYBPhIetrEjilPilE28S0JY=","encryption.expire_at":1777702293517}

View File

@ -1,6 +0,0 @@
{
"buildStage": "compile",
"buildOptions": {
"useBuildWorker": "true"
}
}

View File

@ -1 +0,0 @@
{"name":"Next.js","version":"16.2.4"}

View File

@ -1 +0,0 @@
{"type": "commonjs"}

View File

@ -1 +0,0 @@
[{"name":"generate-buildid","duration":368,"timestamp":609332875152,"id":4,"parentId":1,"tags":{},"startTime":1776492693501,"traceId":"4419ade081f7a7a5"},{"name":"load-custom-routes","duration":826,"timestamp":609332875696,"id":5,"parentId":1,"tags":{},"startTime":1776492693501,"traceId":"4419ade081f7a7a5"},{"name":"create-dist-dir","duration":1467,"timestamp":609332876570,"id":6,"parentId":1,"tags":{},"startTime":1776492693502,"traceId":"4419ade081f7a7a5"},{"name":"clean","duration":1069,"timestamp":609332880708,"id":7,"parentId":1,"tags":{},"startTime":1776492693506,"traceId":"4419ade081f7a7a5"},{"name":"discover-routes","duration":11320,"timestamp":609332931364,"id":8,"parentId":1,"tags":{},"startTime":1776492693557,"traceId":"4419ade081f7a7a5"},{"name":"create-root-mapping","duration":180,"timestamp":609332942834,"id":9,"parentId":1,"tags":{},"startTime":1776492693568,"traceId":"4419ade081f7a7a5"},{"name":"generate-route-types","duration":24323,"timestamp":609332945177,"id":10,"parentId":1,"tags":{},"startTime":1776492693571,"traceId":"4419ade081f7a7a5"},{"name":"public-dir-conflict-check","duration":185,"timestamp":609332969855,"id":11,"parentId":1,"tags":{},"startTime":1776492693595,"traceId":"4419ade081f7a7a5"},{"name":"generate-routes-manifest","duration":2802,"timestamp":609332970199,"id":12,"parentId":1,"tags":{},"startTime":1776492693596,"traceId":"4419ade081f7a7a5"},{"name":"run-turbopack","duration":549715,"timestamp":609332984159,"id":14,"parentId":1,"tags":{"failed":true},"startTime":1776492693610,"traceId":"4419ade081f7a7a5"},{"name":"next-build","duration":810890,"timestamp":609332723082,"id":1,"tags":{"buildMode":"default","version":"16.2.4","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true","failed":true},"startTime":1776492693349,"traceId":"4419ade081f7a7a5"}]

View File

@ -1 +0,0 @@
[{"name":"run-turbopack","duration":549715,"timestamp":609332984159,"id":14,"parentId":1,"tags":{"failed":true},"startTime":1776492693610,"traceId":"4419ade081f7a7a5"},{"name":"next-build","duration":810890,"timestamp":609332723082,"id":1,"tags":{"buildMode":"default","version":"16.2.4","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true","failed":true},"startTime":1776492693349,"traceId":"4419ade081f7a7a5"}]

View File

View File

@ -1,145 +0,0 @@
// Type definitions for Next.js cacheLife configs
declare module 'next/cache' {
export { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache'
export {
updateTag,
revalidateTag,
revalidatePath,
refresh,
} from 'next/dist/server/web/spec-extension/revalidate'
export { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store'
/**
* Cache this `"use cache"` for a timespan defined by the `"default"` profile.
* ```
* stale: 300 seconds (5 minutes)
* revalidate: 900 seconds (15 minutes)
* expire: never
* ```
*
* This cache may be stale on clients for 5 minutes before checking with the server.
* If the server receives a new request after 15 minutes, start revalidating new values in the background.
* It lives for the maximum age of the server cache. If this entry has no traffic for a while, it may serve an old value the next request.
*/
export function cacheLife(profile: "default"): void
/**
* Cache this `"use cache"` for a timespan defined by the `"seconds"` profile.
* ```
* stale: 30 seconds
* revalidate: 1 seconds
* expire: 60 seconds (1 minute)
* ```
*
* This cache may be stale on clients for 30 seconds before checking with the server.
* If the server receives a new request after 1 seconds, start revalidating new values in the background.
* If this entry has no traffic for 1 minute it will expire. The next request will recompute it.
*/
export function cacheLife(profile: "seconds"): void
/**
* Cache this `"use cache"` for a timespan defined by the `"minutes"` profile.
* ```
* stale: 300 seconds (5 minutes)
* revalidate: 60 seconds (1 minute)
* expire: 3600 seconds (1 hour)
* ```
*
* This cache may be stale on clients for 5 minutes before checking with the server.
* If the server receives a new request after 1 minute, start revalidating new values in the background.
* If this entry has no traffic for 1 hour it will expire. The next request will recompute it.
*/
export function cacheLife(profile: "minutes"): void
/**
* Cache this `"use cache"` for a timespan defined by the `"hours"` profile.
* ```
* stale: 300 seconds (5 minutes)
* revalidate: 3600 seconds (1 hour)
* expire: 86400 seconds (1 day)
* ```
*
* This cache may be stale on clients for 5 minutes before checking with the server.
* If the server receives a new request after 1 hour, start revalidating new values in the background.
* If this entry has no traffic for 1 day it will expire. The next request will recompute it.
*/
export function cacheLife(profile: "hours"): void
/**
* Cache this `"use cache"` for a timespan defined by the `"days"` profile.
* ```
* stale: 300 seconds (5 minutes)
* revalidate: 86400 seconds (1 day)
* expire: 604800 seconds (1 week)
* ```
*
* This cache may be stale on clients for 5 minutes before checking with the server.
* If the server receives a new request after 1 day, start revalidating new values in the background.
* If this entry has no traffic for 1 week it will expire. The next request will recompute it.
*/
export function cacheLife(profile: "days"): void
/**
* Cache this `"use cache"` for a timespan defined by the `"weeks"` profile.
* ```
* stale: 300 seconds (5 minutes)
* revalidate: 604800 seconds (1 week)
* expire: 2592000 seconds (1 month)
* ```
*
* This cache may be stale on clients for 5 minutes before checking with the server.
* If the server receives a new request after 1 week, start revalidating new values in the background.
* If this entry has no traffic for 1 month it will expire. The next request will recompute it.
*/
export function cacheLife(profile: "weeks"): void
/**
* Cache this `"use cache"` for a timespan defined by the `"max"` profile.
* ```
* stale: 300 seconds (5 minutes)
* revalidate: 2592000 seconds (1 month)
* expire: 31536000 seconds (365 days)
* ```
*
* This cache may be stale on clients for 5 minutes before checking with the server.
* If the server receives a new request after 1 month, start revalidating new values in the background.
* If this entry has no traffic for 365 days it will expire. The next request will recompute it.
*/
export function cacheLife(profile: "max"): void
/**
* Cache this `"use cache"` using a custom timespan.
* ```
* stale: ... // seconds
* revalidate: ... // seconds
* expire: ... // seconds
* ```
*
* This is similar to Cache-Control: max-age=`stale`,s-max-age=`revalidate`,stale-while-revalidate=`expire-revalidate`
*
* If a value is left out, the lowest of other cacheLife() calls or the default, is used instead.
*/
export function cacheLife(profile: {
/**
* This cache may be stale on clients for ... seconds before checking with the server.
*/
stale?: number,
/**
* If the server receives a new request after ... seconds, start revalidating new values in the background.
*/
revalidate?: number,
/**
* If this entry has no traffic for ... seconds it will expire. The next request will recompute it.
*/
expire?: number
}): void
import { cacheTag } from 'next/dist/server/use-cache/cache-tag'
export { cacheTag }
export const unstable_cacheTag: typeof cacheTag
export const unstable_cacheLife: typeof cacheLife
}

View File

@ -1,88 +0,0 @@
// This file is generated automatically by Next.js
// Do not edit this file manually
type AppRoutes = "/" | "/about" | "/docs" | "/homepage" | "/network" | "/network/api" | "/network/rooms" | "/notify" | "/pricing" | "/pricing/enterprise" | "/pricing/faq" | "/search" | "/skills" | "/skills/docs" | "/skills/publish" | "/solutions" | "/solutions/governance" | "/solutions/memory" | "/solutions/rooms"
type PageRoutes = never
type LayoutRoutes = "/homepage" | "/notify" | "/project" | "/project/repo" | "/repository" | "/repository/settings" | "/settings" | "/workspace"
type RedirectRoutes = never
type RewriteRoutes = never
type Routes = AppRoutes | PageRoutes | LayoutRoutes | RedirectRoutes | RewriteRoutes
interface ParamMap {
"/": {}
"/about": {}
"/docs": {}
"/homepage": {}
"/network": {}
"/network/api": {}
"/network/rooms": {}
"/notify": {}
"/pricing": {}
"/pricing/enterprise": {}
"/pricing/faq": {}
"/project": {}
"/project/repo": {}
"/repository": {}
"/repository/settings": {}
"/search": {}
"/settings": {}
"/skills": {}
"/skills/docs": {}
"/skills/publish": {}
"/solutions": {}
"/solutions/governance": {}
"/solutions/memory": {}
"/solutions/rooms": {}
"/workspace": {}
}
export type ParamsOf<Route extends Routes> = ParamMap[Route]
interface LayoutSlotMap {
"/homepage": never
"/notify": never
"/project": never
"/project/repo": never
"/repository": never
"/repository/settings": never
"/settings": never
"/workspace": never
}
export type { AppRoutes, PageRoutes, LayoutRoutes, RedirectRoutes, RewriteRoutes, ParamMap }
declare global {
/**
* Props for Next.js App Router page components
* @example
* ```tsx
* export default function Page(props: PageProps<'/blog/[slug]'>) {
* const { slug } = await props.params
* return <div>Blog post: {slug}</div>
* }
* ```
*/
interface PageProps<AppRoute extends AppRoutes> {
params: Promise<ParamMap[AppRoute]>
searchParams: Promise<Record<string, string | string[] | undefined>>
}
/**
* Props for Next.js App Router layout components
* @example
* ```tsx
* export default function Layout(props: LayoutProps<'/dashboard'>) {
* return <div>{props.children}</div>
* }
* ```
*/
type LayoutProps<LayoutRoute extends LayoutRoutes> = {
params: Promise<ParamMap[LayoutRoute]>
children: React.ReactNode
} & {
[K in LayoutSlotMap[LayoutRoute]]: React.ReactNode
}
}

View File

@ -1,286 +0,0 @@
// This file is generated automatically by Next.js
// Do not edit this file manually
// This file validates that all pages and layouts export the correct types
import type { AppRoutes, LayoutRoutes, ParamMap } from "./routes.js"
import type { ResolvingMetadata, ResolvingViewport } from "next/types.js"
type AppPageConfig<Route extends AppRoutes = AppRoutes> = {
default: React.ComponentType<{ params: Promise<ParamMap[Route]> } & any> | ((props: { params: Promise<ParamMap[Route]> } & any) => React.ReactNode | Promise<React.ReactNode> | never | void | Promise<void>)
generateStaticParams?: (props: { params: ParamMap[Route] }) => Promise<any[]> | any[]
generateMetadata?: (
props: { params: Promise<ParamMap[Route]> } & any,
parent: ResolvingMetadata
) => Promise<any> | any
generateViewport?: (
props: { params: Promise<ParamMap[Route]> } & any,
parent: ResolvingViewport
) => Promise<any> | any
metadata?: any
viewport?: any
}
type LayoutConfig<Route extends LayoutRoutes = LayoutRoutes> = {
default: React.ComponentType<LayoutProps<Route>> | ((props: LayoutProps<Route>) => React.ReactNode | Promise<React.ReactNode> | never | void | Promise<void>)
generateStaticParams?: (props: { params: ParamMap[Route] }) => Promise<any[]> | any[]
generateMetadata?: (
props: { params: Promise<ParamMap[Route]> } & any,
parent: ResolvingMetadata
) => Promise<any> | any
generateViewport?: (
props: { params: Promise<ParamMap[Route]> } & any,
parent: ResolvingViewport
) => Promise<any> | any
metadata?: any
viewport?: any
}
// Validate ../../src/app/about/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/about">> = Specific
const handler = {} as typeof import("../../src/app/about/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/docs/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/docs">> = Specific
const handler = {} as typeof import("../../src/app/docs/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/homepage/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/homepage">> = Specific
const handler = {} as typeof import("../../src/app/homepage/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/network/api/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/network/api">> = Specific
const handler = {} as typeof import("../../src/app/network/api/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/network/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/network">> = Specific
const handler = {} as typeof import("../../src/app/network/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/network/rooms/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/network/rooms">> = Specific
const handler = {} as typeof import("../../src/app/network/rooms/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/notify/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/notify">> = Specific
const handler = {} as typeof import("../../src/app/notify/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/">> = Specific
const handler = {} as typeof import("../../src/app/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/pricing/enterprise/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/pricing/enterprise">> = Specific
const handler = {} as typeof import("../../src/app/pricing/enterprise/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/pricing/faq/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/pricing/faq">> = Specific
const handler = {} as typeof import("../../src/app/pricing/faq/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/pricing/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/pricing">> = Specific
const handler = {} as typeof import("../../src/app/pricing/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/search/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/search">> = Specific
const handler = {} as typeof import("../../src/app/search/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/skills/docs/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/skills/docs">> = Specific
const handler = {} as typeof import("../../src/app/skills/docs/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/skills/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/skills">> = Specific
const handler = {} as typeof import("../../src/app/skills/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/skills/publish/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/skills/publish">> = Specific
const handler = {} as typeof import("../../src/app/skills/publish/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/solutions/governance/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/solutions/governance">> = Specific
const handler = {} as typeof import("../../src/app/solutions/governance/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/solutions/memory/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/solutions/memory">> = Specific
const handler = {} as typeof import("../../src/app/solutions/memory/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/solutions/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/solutions">> = Specific
const handler = {} as typeof import("../../src/app/solutions/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/solutions/rooms/page.tsx
{
type __IsExpected<Specific extends AppPageConfig<"/solutions/rooms">> = Specific
const handler = {} as typeof import("../../src/app/solutions/rooms/page.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/homepage/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/homepage">> = Specific
const handler = {} as typeof import("../../src/app/homepage/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/notify/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/notify">> = Specific
const handler = {} as typeof import("../../src/app/notify/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/project/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/project">> = Specific
const handler = {} as typeof import("../../src/app/project/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/project/repo/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/project/repo">> = Specific
const handler = {} as typeof import("../../src/app/project/repo/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/repository/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/repository">> = Specific
const handler = {} as typeof import("../../src/app/repository/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/repository/settings/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/repository/settings">> = Specific
const handler = {} as typeof import("../../src/app/repository/settings/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/settings/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/settings">> = Specific
const handler = {} as typeof import("../../src/app/settings/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}
// Validate ../../src/app/workspace/layout.tsx
{
type __IsExpected<Specific extends LayoutConfig<"/workspace">> = Specific
const handler = {} as typeof import("../../src/app/workspace/layout.js")
type __Check = __IsExpected<typeof handler>
// @ts-ignore
type __Unused = __Check
}

View File

@ -19,7 +19,7 @@ use crate::compact::{CompactConfig, CompactService};
use crate::embed::EmbedService;
use crate::error::{AgentError, Result};
use crate::perception::{PerceptionService, SkillEntry, ToolCallEvent};
use crate::tool::{ToolCall, ToolContext, ToolExecutor};
use crate::tool::{ToolCall, ToolContext, ToolExecutor, registry::ToolRegistry};
/// Service for handling AI chat requests in rooms.
pub struct ChatService {
@ -27,6 +27,7 @@ pub struct ChatService {
compact_service: Option<CompactService>,
embed_service: Option<EmbedService>,
perception_service: PerceptionService,
tool_registry: Option<ToolRegistry>,
}
impl ChatService {
@ -36,6 +37,7 @@ impl ChatService {
compact_service: None,
embed_service: None,
perception_service: PerceptionService::default(),
tool_registry: None,
}
}
@ -54,6 +56,11 @@ impl ChatService {
self
}
pub fn with_tool_registry(mut self, registry: ToolRegistry) -> Self {
self.tool_registry = Some(registry);
self
}
#[allow(deprecated)]
pub async fn process(&self, request: AiRequest) -> Result<String> {
let tools: Vec<ChatCompletionTool> = request.tools.clone().unwrap_or_default();
@ -390,6 +397,11 @@ impl ChatService {
)
.with_project(request.project.id);
// Add pre-configured tool registry if available
if let Some(ref registry) = self.tool_registry {
ctx.registry_mut().merge(registry.clone());
}
let executor = ToolExecutor::new();
let results = executor

View File

@ -130,4 +130,9 @@ impl ToolContext {
pub fn registry(&self) -> &ToolRegistry {
&self.inner.registry
}
/// Mutable access to registry for adding tools.
pub fn registry_mut(&mut self) -> &mut ToolRegistry {
&mut Arc::make_mut(&mut self.inner).registry
}
}

View File

@ -24,4 +24,4 @@ pub use call::{ToolCall, ToolCallResult, ToolError, ToolResult};
pub use context::ToolContext;
pub use definition::{ToolDefinition, ToolParam, ToolSchema};
pub use executor::ToolExecutor;
pub use registry::ToolRegistry;
pub use registry::{ToolHandler, ToolRegistry};

View File

@ -92,4 +92,18 @@ impl ToolRegistry {
pub fn is_empty(&self) -> bool {
self.handlers.is_empty()
}
/// Merges another registry's tools into this one.
/// Panics if a tool with the same name already exists.
pub fn merge(&mut self, other: ToolRegistry) {
for (name, handler) in other.handlers {
if self.handlers.contains_key(&name) {
panic!("tool already registered: {}", name);
}
self.handlers.insert(name, handler);
}
for (name, def) in other.definitions {
self.definitions.insert(name, def);
}
}
}

View File

@ -1,6 +1,7 @@
use std::sync::Arc;
use ::agent::chat::ChatService;
use ::agent::tool::ToolRegistry;
use ::agent::task::service::TaskService;
use async_openai::config::OpenAIConfig;
use avatar::AppAvatar;
@ -145,7 +146,9 @@ impl AppService {
.with_api_key(&api_key)
.with_api_base(&base_url);
let client = async_openai::Client::with_config(cfg);
Some(Arc::new(ChatService::new(client)))
let mut registry = ToolRegistry::new();
git_tools::register_all(&mut registry);
Some(Arc::new(ChatService::new(client).with_tool_registry(registry)))
}
(Err(e), _) => {
slog::warn!(logs, "AI chat disabled — {}", e);

View File

@ -1,7 +1,6 @@
use crate::AppService;
use crate::error::AppError;
use chrono::{DateTime, Utc};
use futures::future::join_all;
use models::projects::{
project, MemberRole, project_audit_log, project_member_invitations, project_members,
};
@ -165,13 +164,14 @@ impl AppService {
.count(&self.db)
.await?;
let invitations = join_all(
let invitations = futures::future::join_all(
invitations
.into_iter()
.map(|inv| InvitationResponse::from_model(inv, self.db.writer())),
)
.await;
.collect();
.await
.into_iter()
.collect();
Ok(InvitationListResponse {
invitations,