Skip to content

Commit

Permalink
auth and chat
Browse files Browse the repository at this point in the history
  • Loading branch information
danielcampagnolitg committed Nov 4, 2024
1 parent e18066c commit 5b0e1f0
Show file tree
Hide file tree
Showing 32 changed files with 755 additions and 152 deletions.
100 changes: 50 additions & 50 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,70 @@
<img src="https://public.trafficguard.ai/sophia/banner.png" alt="nous logo"/>
</p>
<p align="center">
<em>The open-source TypeScript platform for autonomous AI agents and LLM based workflows</em>
<em><b>The open-source TypeScript platform for AI agents and LLM based workflows</b></em>
</p>
<p align="center">

The Ancient Greek word <em><b>sophía (σοφία)</b></em> variously translates to "clever, skillful, intelligent, wise"
</p>
## The Sophia Story

The Ancient Greek word <em><b>sophía (σοφία)</b></em> variously translates to "clever, skillful, intelligent, wise"

Sophia started from a simple goal: to harness AI's potential to enhance real-world productivity, born in DevOps and Platform Engineering space. We envisioned a tool that could:
The Sophia platform provides a complete out-of-the box experience for building AI agents and LLM based workflows with TypeScript.

- Automate various processes and support requests, and triage build failures.
- Review code for compliance with standards and best practices.
- Assist with large refactorings, and more.
- [Autonomous agents](https://sophia.dev//autonomous-agents)
- [Software developer agents](https://sophia.dev/software-engineer/)
- [Code review agents](https://sophia.dev/software-engineer/)
- Chat interface
- Chatbots (Slack integration provided)
- Functional callable tools (Filesystem, Jira, Slack, Perplexity, Google Cloud, Gitlab, GitHub and more)
- CLI and Web UI interface
- Run locally or deployed on the cloud with multi-user/SSO
- OpenTelemetry observability

At TrafficGuard we process billions of events a month for our global clients, [increasing their Ad spend ROI](https://www.trafficguard.ai/case-studies?ref=sophia) from bots and other invalid traffic.
Our platform on Google Cloud comprises projects developed in TypeScript, Python, GoogleSQL, PHP and Terraform, deployed from GitLab.
## Autonomous agents

With open source projects typically Python/GitHub focused, and the vendor AI tools being focused in their silos,
we saw a need for TypeScript based tooling which can work across our entire tech stack, and understand the overall architecture.
- Reasoning/planning inspired from Google's [Self-Discover](https://arxiv.org/abs/2402.03620) and other papers
- Memory and function call history for complex workflows
- Iterative planning with hierarchical task decomposition
- Sandboxed execution of generated code for multi-step function calling and logic
- LLM function schemas auto-generated from source code
- Human-in-the-loop for budget control, agent initiated questions and error handling

Through its evolution we've designed nous as a flexible platform for the TypeScript community to expand and support the use cases and integrations of your choice.
## Software developer agents

Our design choice of Firestore for the initial database implementation, with Cloud Run, provides a scale-to-zero solution with zero-cost using the free tier.
With the intention to support uses cases such as your own custom personal assistant, always available via mobile.
- Code Editing Agent:
- Auto-detection of project initialization, compile, test and lint
- Task file selection agent
- Code editing loop with compile, lint, test, fix (editing delegates to [Aider](https://aider.chat/))
- Compile error analyser can search online, add additional files and packages
- Review the changes with an additional code editing loop if required.
- Software Engineer Agent (For issue to Pull Request workflow):
- Find the appropriate repository from GitLab/GitHub
- Clone and create branch
- Call the Code Editing Agent
- Create merge request
- Code review agents
- Query repository agent

## Features
## Chatbots

Some of the key features include:
- Slack chatbot

## Flexible run/deploy options

- CLI interface
- Web interface
- Scale-to-zero deployment on Firestore & Cloud Run
- Multi-user SSO enterprise deployment (with [Google Cloud IAP](https://cloud.google.com/security/products/iap))

## LLM support

OpenAI, Anthropic (native & Vertex), Gemini, Groq, Fireworks, Together.ai, DeepSeek, Ollama, Cerebras, X.ai


- Filesystem, Jira, Slack, Perplexity, Gitlab and more

- Advanced autonomous agents
- Reasoning/planning inspired from Google's [Self-Discover](https://arxiv.org/abs/2402.03620) paper
- Memory and function call history for complex workflows
- Iterative planning with hierarchical task decomposition
- Two LLM-independent function calling options:
- Custom XML-based function calling
- Sandboxed execution of generated code with multi-step function calling and logic
- Opportunistically can significantly reduce cost and latency compared to LLM-native/XML function calling
- LLM function schemas auto-generated from source code
- Function callable integrations:
- Filesystem, Jira, Slack, Perplexity, Gitlab and more
- Supports multiple LLMs/Services:
- OpenAI, Anthropic (native & Vertex), Gemini, Groq, Fireworks, Together.ai, DeepSeek, Ollama, Cerebras
- CLI and Web interface
- Human-in-the-loop for:
- Budget control
- Agent initiated questions
- Error handling
- Flexible deployment options:
- Run locally from the command line or through the web UI
- Scale-to-zero deployment on Firestore & Cloud Run
- Multi-user SSO enterprise deployment (with [Google Cloud IAP](https://cloud.google.com/security/products/iap))
- Observability with OpenTelemetry tracing
- Code Editing Agent:
- Auto-detection of project initialization, compile, test and lint
- Find the relevant files to edit and perform initial analysis
- Code editing loop with compile, lint, test, fix (editing delegates to [Aider](https://aider.chat/))
- Compile error analyser can search online, add additional files and packages
- Review the changes with an additional code editing loop if required.
- Software Engineer Agent:
- Find the appropriate repository from GitLab/GitHub
- Clone and create branch
- Call the Code Editing Agent
- Create merge request

- Code Review agent:
- Configurable code review guidelines
- Posts comments on GitLab merge requests at the appropriate line with suggested changes
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import {
PreloadAllModules,
provideRouter,
provideRouter, withDebugTracing,
withInMemoryScrolling,
withPreloading,
} from '@angular/router';
Expand All @@ -31,6 +31,7 @@ export const appConfig: ApplicationConfig = {
},
provideRouter(
appRoutes,
// withDebugTracing(),
withPreloading(PreloadAllModules),
withInMemoryScrolling({ scrollPositionRestoration: 'enabled' })
),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const appRoutes: Route[] = [
children: [
{path: 'example', loadChildren: () => import('app/modules/admin/home/home.routes')},
{path: 'profile', loadChildren: () => import('app/modules/profile/profile.routes')},
{path: 'apps/chat', loadChildren: () => import('app/modules/admin/apps/chat/chat.routes')},
{path: 'chat', loadChildren: () => import('app/modules/admin/apps/chat/chat.routes')},
{path: 'agents', loadChildren: () => import('app/modules/agents/agent.routes')},
{path: 'code-reviews', loadChildren: () => import('app/modules/code-review/code-review.routes')},
{path: 'actions', loadChildren: () => import('app/modules/actions/actions.routes')},
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/app/core/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { AuthUtils } from 'app/core/auth/auth.utils';
import { UserService } from 'app/core/user/user.service';
import {catchError, map, Observable, of, switchMap, tap, throwError} from 'rxjs';
import {environment} from "../../../environments/environment";
import { catchError, map, Observable, of, switchMap, tap, throwError } from 'rxjs';
import { environment} from "../../../environments/environment";
import { SharedTypes } from "../../shared";

@Injectable({ providedIn: 'root' })
export class AuthService {
private _authenticated: boolean = false;
private _httpClient = inject(HttpClient);
private _userService = inject(UserService);
private sharedtypes = inject(SharedTypes);

// -----------------------------------------------------------------------------------------------------
// @ Accessors
Expand Down Expand Up @@ -56,10 +58,12 @@ export class AuthService {
signIn(credentials: { email: string; password: string }): Observable<any> {
// Throw error, if the user is already logged in
if (this._authenticated) {
// TODO check if logging in as the same user, if so redirect to home
console.log('already authenticated')
return throwError('User is already logged in.');
}

return this._httpClient.post('api/auth/sign-in', credentials).pipe(
return this._httpClient.post('/api/auth/signin', credentials).pipe( //
switchMap((response: any) => {
// Store the access token in the local storage
this.accessToken = response.accessToken;
Expand Down Expand Up @@ -134,12 +138,10 @@ export class AuthService {
* @param user
*/
signUp(user: {
name: string;
email: string;
password: string;
company: string;
}): Observable<any> {
return this._httpClient.post('api/auth/sign-up', user);
return this._httpClient.post('/api/auth/signup', user); // this.sharedtypes.routes.AUTH_SIGNUP
}

/**
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/app/core/auth/auth.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ export class AuthUtils {
*/
private static _getTokenExpirationDate(token: string): Date | null {
// Get the decoded token
const decodedToken = this._decodeToken(token);
let decodedToken;
try {
decodedToken = this._decodeToken(token);
} catch(e) {
return null;
}


// Return if the decodedToken doesn't have an 'exp' field
if (!decodedToken.hasOwnProperty('exp')) {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/core/auth/guards/noAuth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const NoAuthGuard: CanActivateFn | CanActivateChildFn = (
.pipe(
switchMap((authenticated) => {
// If the user is authenticated...
console.log(`NoAuthGuard ${authenticated}`)
if (authenticated) {
return of(router.parseUrl(''));
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/mock-api/common/navigation/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
title: 'Chat',
type: 'basic',
icon: 'heroicons_outline:chat-bubble-bottom-center-text',
link: '/ui/apps/chat',
link: '/ui/chat',
},
// {
// id: 'assistants',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/mock-api/pages/activities/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const activities = [
description: '<strong>Tina Harris</strong> started a chat with you',
date: now.minus({ day: 1 }).toISO(), // 1 day ago,
linkedContent: 'Go to Chat (Tina Harris)',
link: '/apps/chat/5636c0ba-fa47-42ca-9160-27340583041e',
link: '/chat/5636c0ba-fa47-42ca-9160-27340583041e',
useRouter: true,
},
{
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/modules/admin/apps/chat/chat.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const conversationResolver = (
const parentUrl = state.url.split('/').slice(0, -1).join('/');

// Navigate to there
router.navigateByUrl(parentUrl);
router.navigateByUrl(parentUrl).catch(console.error);

// Throw an error
return throwError(error);
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/modules/admin/apps/chat/chat.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export class ChatService {
*/
getChatById(id: string): Observable<any> {
if(!id?.trim() || id === 'new') {
console.log(`new or nullish chat id "${id}"`)
const chat: Chat = {messages:[], id: 'new', title: '', updatedAt: Date.now() }
this._chat.next(chat);
return this._chats
Expand Down Expand Up @@ -150,7 +151,7 @@ export class ChatService {
take(1),
switchMap((chats) =>
this._httpClient
.patch<Chat>('api/apps/chat/chat', {
.patch<Chat>('api/chat/chat', {
id,
chat,
})
Expand Down Expand Up @@ -193,6 +194,7 @@ export class ChatService {
* Reset the selected chat
*/
resetChat(): void {
console.log('chat.service resetChat')
this._chat.next(null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,15 @@ export class ConversationComponent implements OnInit, OnDestroy, AfterViewInit {
.pipe(takeUntil(this._unsubscribeAll))
.subscribe(params => {
const chatId = params['id'];

console.log(`route param id: ${chatId}`)
if (chatId === 'new' || !chatId) {
// If 'new' or no ID, reset the chat
this.resetChat();
}
});

this.userService.user$.subscribe(user => {
console.log(`$user ${user.defaultChatLlmId}`)
this.defaultChatLlmId = user.defaultChatLlmId;
this.setLlmSelector();
});
Expand All @@ -178,6 +179,11 @@ export class ConversationComponent implements OnInit, OnDestroy, AfterViewInit {
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((chat: Chat) => {
console.log(chat)
// if(chat === null) {
// // This chat was deleted
// this.router.navigate(['/ui/apps/chat/new']).catch(console.error);
// return;
// }
this.chat = clone(chat) || { id: 'new', messages: [], title: '', updatedAt: Date.now() };

this.setLlmSelector();
Expand Down Expand Up @@ -223,7 +229,9 @@ export class ConversationComponent implements OnInit, OnDestroy, AfterViewInit {


setLlmSelector() {
console.log(this.chat, this.defaultChatLlmId)
if ((!this.chat || this.chat.id === 'new') && this.defaultChatLlmId) {
console.log('setting default llm')
this.llmId = this.defaultChatLlmId;
} else if (this.chat?.messages.length > 0) {
// Set the LLM selector as the LLM used to send the last message
Expand Down Expand Up @@ -251,7 +259,9 @@ export class ConversationComponent implements OnInit, OnDestroy, AfterViewInit {
* Reset the chat
*/
resetChat(): void {
console.log('resetChat')
this._chatService.resetChat();
// this.router.navigate(['/ui/apps/chat']).catch(console.error);
}

/**
Expand Down Expand Up @@ -309,7 +319,7 @@ export class ConversationComponent implements OnInit, OnDestroy, AfterViewInit {
this._chatService.createChat(message, this.llmId).subscribe(async (chat: Chat) => {
clearInterval(this.generatingTimer)
this.generating = false;
this.router.navigate([`/ui/apps/chat/${chat.id}`]).catch(console.error);
this.router.navigate([`/ui/chat/${chat.id}`]).catch(console.error);
});
// TODO catch errors
return;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/modules/assistants/assistant.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const conversationResolver = (
const parentUrl = state.url.split('/').slice(0, -1).join('/');

// Navigate to there
router.navigateByUrl(parentUrl);
router.navigateByUrl(parentUrl).catch(console.error);

// Throw an error
return throwError(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export class AssistantComponent implements OnInit, OnDestroy {
if (this.chat && this.chat.id) {
this._assistantService.deleteChat(this.chat.id).subscribe(() => {
this.resetChat();
this.router.navigate(['/ui/apps/chat']).catch(console.error);
this.router.navigate(['/ui/chat']).catch(console.error);
});
}
}
Expand Down Expand Up @@ -270,7 +270,7 @@ export class AssistantComponent implements OnInit, OnDestroy {
this._changeDetectorRef.markForCheck();
// TODO handle error, set the message back to the messageInput and remove from chat.messages
this._assistantService.createChat(message, this.llmId).subscribe(async (chat: AssistantChat) => {
this.router.navigate([`/ui/apps/chat/${chat.id}`]).catch(console.error);
this.router.navigate([`/ui/chat/${chat.id}`]).catch(console.error);
});

return;
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/modules/assistants/assistants.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class AssistantsService {
take(1),
switchMap((chats) =>
this._httpClient
.patch<AssistantChat>('api/apps/chat/chat', {
.patch<AssistantChat>('api/chat/chat', {
id,
chat,
})
Expand Down Expand Up @@ -188,7 +188,7 @@ export class AssistantsService {
take(1),
switchMap((chats) =>
this._httpClient
.patch<AssistantChat>('api/apps/chat/chat', {
.patch<AssistantChat>('api/chat/chat', {
id,
chat,
})
Expand Down
Loading

0 comments on commit 5b0e1f0

Please sign in to comment.