Skip to content

Commit

Permalink
Rename pythonAgent to codegenAgent. UI fixes. Doc updates
Browse files Browse the repository at this point in the history
  • Loading branch information
danielcampagnolitg committed Oct 7, 2024
1 parent 5295d40 commit 5c1f964
Show file tree
Hide file tree
Showing 42 changed files with 522 additions and 335 deletions.
2 changes: 1 addition & 1 deletion bin/configure
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

pyenv install $(cat .python-version)
python -m pip install --upgrade pip
pip install aider-chat youtube-transcript-api
pip install aider-chat google-cloud-aiplatform "anthropic[vertex]" youtube-transcript-api


# Server Node.js setup ---------------------------------
Expand Down
16 changes: 9 additions & 7 deletions docs/docs/agent-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@

### 1. Autonomous agents

Sophia comes with two fully autonomous agents (XML and Python/dynamic), which applying reasoning to break down
Sophia comes with two autonomous agents (XML and CodeGen), which applying reasoning to break down
a user request into a plan to be completed by the available function calls.

Function calls may be to API integrations or create sub-agents.

### 2. Workflow agents

Workflow agents typically have the majority of the high level control flow logic in code, and the results of the LLM calls
may influence the conditional control flow through the workflow. This includes the Software Developer/Code Editing agents.
Workflow agents have the control flow logic in code, and the results of the LLM calls
may determine the conditional control flow through the workflow. This includes the Software Developer/Code Editing agents.

An autonomous agent may start a workflow agent via a function call, and a workflow may start an autonomous agent.

## Agent context

The code makes use of `AsyncLocalStorage`, which is similar to `ThreadLocal` in Java and `threading.local()` in Python,
to provide easy lookup of agent state, current user, tool configuration, default LLMs.
The codebase makes use of `AsyncLocalStorage`, which is similar to `ThreadLocal` in Java and `threading.local()` in Python,
to provide easy lookup of agent state, current user, tool configuration, and default LLMs.

This does require the agent code to run within a context
```typescript
Expand Down Expand Up @@ -54,6 +56,6 @@ export async function runAgentWorkflow(runConfig: RunAgentConfig, workflow: (age
}
```

The agent has three LLMs configured for easy, medium and hard tasks, so its simple to evaluate different LLMs at a particular level of capability.
The agent has three LLMs configured for easy, medium and hard tasks, so it's simple to evaluate different LLMs at a particular level of capability.

This was partly inspired when Claude 3 was released, having the Haiku, Sonnet and Claude models.
This was partly inspired when Claude 3 was released, having the Haiku, Sonnet and Claude models.
9 changes: 9 additions & 0 deletions docs/docs/chat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Chat

A basic chat interface like chatgpt.com or claude.ai is provided where you can select the LLM model (or multi-agent model) used for each message generation.

More features are planned to be added in the future.

![List chats](https://public.trafficguard.ai/sophia/chat1.png)

![AI chat](https://public.trafficguard.ai/sophia/chat2.png)
155 changes: 12 additions & 143 deletions docs/docs/code-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,158 +2,27 @@

Sophia has support for AI code reviews of GitLab merge requests. Adding GitHub support is a good candidate for using the Code Editor agent to assist with!

For the current working proof-of-concept, the configuration files are located in the [/resources](https://github.com/TrafficGuard/nous/tree/preview/resources/codeReview) folder. The next step will to store the configuration in a database.
AI code reviews are useful for guidelines where a lint rule doesn't exist yet, or it can't easily be codified.

Code review are useful for guidelines where a lint rule doesn't exist yet, or it can't easily be codified.

It can be useful when a lint rule does exist, but there are many violations which need be fixed in a project before the rule can be enabled at the error level.
It can also be useful when a lint rule does exist, but there are many violations which need be fixed in a project before the rule can be enabled at the error level.
In this case the AI reviewer can stop additional violations of a lint rule being added to the code base.

The configuration has two elements to filter diffs to review to minimize LLM costs.
Each configuration has three filters to determine if a review will be done on a diff to minimize LLM costs.

- file_extensions: The file must end with one of the provided file extension(s)
- requires: The diff must contain the provided text.
- Included file extensions: The filename must end with one of the file extension(s)
- Required text in diff: The diff must contain the provided text.
- Project paths: If any values are provided the project path must match one of the path globs.

Lines numbers are added to the diffs as comments every 10 lines and in blank lines to assist the AI in providing the correct line number to add the comment.

```XML
<code_review xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd">
<description>
All TypeScript functions should have the typing for the return type. If it's possible to confidently infer the return
type, then include it in the review comment, otherwise use the placeholder TODO. If the function is async then ensure
the return type is a Promise.
</description>
<file_extensions>
<include>.ts</include>
</file_extensions>
<requires>
<text>) {</text>
</requires>
<examples>
<example>
<code><![CDATA[
async function sendBirthdayGreeting(user: User | null) {
if (!user) throw new Error('User was null');
if (user.dateOfBirth < Date.now()) throw new Error(`dateOfBirth in the future for user ${user.id}`);
if (dayOfYear(user.dateOfBirth) === dayOfYear(Date.now())) {
await this.emailService.sendEmail(this.createBdayEmail(user));
}
}
]]></code>
<review_comment><![CDATA[
Functions must specify a return type.
```
async sendBirthdayGreeting(user: User | null): Promise<void> {
```
]]></review_comment>
</example>
<example>
<code><![CDATA[
async function processAsync() {
return buildComplexTypeAsync()
}
]]></code>
<review_comment><![CDATA[
Functions must specify a return type.
```
async function processAsync(): Promise<TODO> {
```
]]></review_comment>
</example>
<example>
<code><![CDATA[
function processSync() {
return buildComplexTypeSync()
}
]]></code>
<review_comment><![CDATA[
Functions must specify a return type.
```
function processSync(): TODO {
```
]]></review_comment>
</example>
</examples>
</code_review>
```
![Code review config](https://public.trafficguard.ai/sophia/code-review.png)

# GitLab Configuration

```xml
<code_review xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd">
<description>
Prefer returning/throwing early, and handling null/empty cases first.
If an else block throws or returns, switch the ordering of the if/else blocks, which will result in not having an else block.
The line number should be the line of the `if` statement.
If there are multiple nested if/else block violations then leave a single review comment covering all violations.
</description>
<file_extensions>
<include>.ts</include>
<include>.js</include>
</file_extensions>
<requires>
<text>else {</text>
</requires>
<examples>
<example>
<code><![CDATA[
async sendBirthdayGreeting(user: User | null): Promise<void> {
if (user) {
if(user.dateOfBirth > Date.now()) {
if (dayOfYear(user.dateOfBirth) === dayOfYear(Date.now())) {
await this.emailService.sendEmail(this.createBdayEmail(user));
}
} else {
throw new Error(`dateOfBirth in the future for user ${user.id}`);
}
} else {
throw new Error('User was null');
}
}
]]></code>
<review_comment><![CDATA[
Handle exceptional cases first and exit early to simplify the code flow.
```
async sendBirthdayGreeting(user: User | null): Promise<void> {
if (!user) throw new Error('User was null');
if (user.dateOfBirth < Date.now()) throw new Error(`dateOfBirth in the future for user ${user.id}`);
You will need to create a webhook in GitLab for the group(s)/project(s) you want to have the AI reviews enabled on.

if (dayOfYear(user.dateOfBirth) === dayOfYear(Date.now())) {
await this.emailService.sendEmail(this.createBdayEmail(user));
}
}
```
]]></review_comment>
</example>
<example>
<code><![CDATA[
async function deleteReservation(): Promise<boolean> {
const reservations = this.getReservations();
if (reservations.length) {
await this.reservationsClient.deleteReservation({ name: reservations[0].name });
return true;
} else {
logger.info("No BigQuery reservation found.");
return false;
}
}
]]></code>
<review_comment><![CDATA[
Handle exceptional cases first and exit early to simplify the code flow.
```
async function deleteReservation(): Promise<boolean> {
const reservations = this.getReservations();
In `Settings -> Webhooks` configure a webhook to your Sophia deployment with the *Merge request events* checked.

if (!reservations.length) {
logger.info("No BigQuery reservation found.");
return false;
}
![Gitlab webhook](https://public.trafficguard.ai/sophia/gitlab-webhook1.png)

await this.reservationsClient.deleteReservation({ name: reservations[0].name });
return true;
}
```
]]></review_comment>
</example>
</examples>
</code_review>
```
![Gitlab webhook](https://public.trafficguard.ai/sophia/gitlab-webhook2.png)
7 changes: 4 additions & 3 deletions docs/docs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ The `@funcClass(__filename)` annotation must be on the class so ts-morph can fin
The `@func()` annotation must be on each class method to be exposed as a LLM callable function.

If the schema files don't exist at runtime then they will automatically be generated. To improve startup time
the schema files are cached under the folder `.sophia/functions` and only re-built if the source file modified date is newer.
Also, the schema files can be generated at build time with the `npm run functionSchemas` script.
the schema files are cached under the folder `.sophia/functions` and only re-built if the source file modified date is newer.

The schema files can be generated at build time with the `npm run functionSchemas` script.

Function calling agents can transform the object implementing the [FunctionSchema](https://github.com/TrafficGuard/sophia/blob/main/src/functionSchema/functions.ts#L13)
interface into the format required, e.g. the custom XML format, or native function calling types for OpenAI, Anthropic, Gemini etc.
interface into the format required, e.g. the custom XML format, or (not yet implemented) native function calling types for OpenAI, Anthropic, Gemini etc.

The `@func` annotation also adds OpenTelemetry tracing to the function call.

Expand Down
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ nav:
- code-review.md
- chatbot.md
- integrations.md
- chat.md
- roadmap.md
- Blog:
- blog/index.md
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/app/@shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export * from '@ngneat/until-destroy';
export type Data<T> = {
data: T;
};

export type AgentType = 'xml' | 'codegen';
3 changes: 2 additions & 1 deletion frontend/src/app/agents/agents.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HttpClient } from '@angular/common/http';
import { filter, map } from 'rxjs/operators';
import { MatTableDataSource } from '@angular/material/table';
import { environment } from '@env/environment';
import { AgentType } from '@shared';

export type TaskLevel = 'easy' | 'medium' | 'hard' | 'xhard';

Expand Down Expand Up @@ -78,7 +79,7 @@ export interface AgentContext {
/** Empty string in single-user mode */
userId: string;
userEmail?: string;
type: 'xml' | 'python';
type: AgentType;
state: AgentRunningState;
inputPrompt: string;
userPrompt: string;
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ const routes: Routes = [
loadChildren: () => import('./code-review/code-review.module').then((m) => m.CodeReviewModule),
},
]),
Shell.childRoutes([
{ path: 'code', loadChildren: () => import('./code/code.module').then(m => m.CodeModule) },
]),
Shell.childRoutes([{ path: 'code', loadChildren: () => import('./code/code.module').then((m) => m.CodeModule) }]),
// Fallback when no prior route is matched
{ path: '**', redirectTo: '', pathMatch: 'full' },
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@
</mat-select>
</mat-form-field>

<button
mat-fab
color="primary"
(click)="submit()"
[disabled]="!chatForm.get('message')?.value || isSending || !chatForm.get('selectedLlm')?.value"
>
<button mat-fab color="primary" (click)="submit()" [disabled]="!chatForm.valid || isSending">
<mat-icon *ngIf="!isSending">send</mat-icon>
<mat-spinner *ngIf="isSending" diameter="24"></mat-spinner>
</button>
Expand Down
Loading

0 comments on commit 5c1f964

Please sign in to comment.