Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to reduce coupling between modules. Add agent parent/child p… #38

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,22 @@ Use async/await where possible

Test exceptional cases first and return/throw early.

Never edit files name CONVENTIONS.md or .cursorrules

# Test code standards

Unit test files should be in the same directory as the source file.

Any usage of chai-as-promised should use async/await
```
it('should work well with async/await', async () => {
(await Promise.resolve(42)).should.equal(42)
await Promise.reject(new Error()).should.be.rejectedWith(Error);
});
```

# Tool/function classes

Function classes with the @funcClass(__filename) must only have the default constructor.

Always use the Filesystem class in src/functions/storage/filesystem.ts to read/search/write to the local filesystem.
4 changes: 2 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sophia/ui",
"version": "0.1.0",
"version": "0.2.0",
"description": "Sophia AI platform",
"author": "https://themeforest.net/user/srcn, Daniel Campagnoli, TrafficGuard Pty Ltd, and contributors",
"license": "https://themeforest.net/licenses/standard",
Expand Down
26 changes: 20 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@trafficguard/sophia",
"version": "0.1.0",
"version": "0.2.0",
"description": "AI agent & LLM app platform",
"private": true,
"type": "commonjs",
Expand All @@ -19,6 +19,7 @@
"py": " node --env-file=variables/local.env -r ts-node/register src/cli/py.ts",
"code": " node --env-file=variables/local.env -r ts-node/register src/cli/code.ts",
"query": " node --env-file=variables/local.env -r ts-node/register src/cli/query.ts",
"repos": " node --env-file=variables/local.env -r ts-node/register src/cli/repos.ts",
"scrape": " node --env-file=variables/local.env -r ts-node/register src/cli/scrape.ts",
"slack": " node --env-file=variables/local.env -r ts-node/register src/cli/slack.ts",
"summarize": "node --env-file=variables/local.env -r ts-node/register src/cli/summarize.ts",
Expand All @@ -32,7 +33,6 @@
"functionSchemas": "node --env-file=variables/local.env -r ts-node/register src/generateFunctionSchemas.ts",
"start": " node -r ts-node/register src/index.ts",
"start:local": "node -r ts-node/register --env-file=variables/local.env --inspect=0.0.0.0:9229 src/index.ts",
"start:file": " node -r ts-node/register --env-file=variables/local.env src/index.ts --db=file",
"emulators": "gcloud emulators firestore start --host-port=127.0.0.1:8243",
"test": "npm run test:unit && echo \"No system or integration tests\"",
"test:ci": "firebase emulators:exec --only firestore \"npm run test\"",
Expand Down Expand Up @@ -92,6 +92,7 @@
"@types/axios": "^0.14.0",
"@types/bcrypt": "^5.0.2",
"@types/chai": "^4.3.16",
"@types/micromatch": "^4.0.9",
"@types/pg": "^8.11.4",
"ai": "3.4.20",
"api": "^6.1.1",
Expand All @@ -117,7 +118,7 @@
"ignore": "^5.3.1",
"jsdom": "^24.0.0",
"lodash": "^4.17.20",
"micromatch": "^4.0.7",
"micromatch": "^4.0.8",
"module-alias": "^2.2.2",
"openai": "^4.28.4",
"pino": "^8.18.0",
Expand Down
10 changes: 4 additions & 6 deletions src/agent/LlmFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Agent } from '#agent/agentFunctions';
import { functionFactory } from '#functionSchema/functionDecorators';
import { FUNC_SEP, FunctionSchema, getFunctionSchemas } from '#functionSchema/functions';
import { FileSystemRead } from '#functions/storage/FileSystemRead';
import { ToolType, toolType } from '#functions/toolType';
import { FunctionCall } from '#llm/llm';
import { logger } from '#o11y/logger';

import { FileSystemService } from '#functions/storage/fileSystemService';
import { GetToolType, ToolType, toolType } from '#functions/toolType';

import { functionFactory } from '#functionSchema/functionDecorators';
import { FileSystemRead } from '#functions/storage/FileSystemRead';

/**
* Holds the instances of the classes with function callable methods.
*/
Expand All @@ -28,6 +25,7 @@ export class LlmFunctions {
}

fromJSON(obj: any): this {
if (!obj) return this;
const functionClassNames = (obj.functionClasses ?? obj.tools) as string[]; // obj.tools for backward compat with dev version
for (const functionClassName of functionClassNames) {
const ctor = functionFactory()[functionClassName];
Expand Down
2 changes: 1 addition & 1 deletion src/agent/agentContext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { deserializeAgentContext, serializeContext } from '#agent/agentSerializa
import { FileSystemRead } from '#functions/storage/FileSystemRead';
import { LlmTools } from '#functions/util';
import { GPT4o } from '#llm/services/openai';
import { appContext } from '../app';
import { appContext } from '../applicationContext';
import { functionRegistry } from '../functionRegistry';

describe('agentContext', () => {
Expand Down
2 changes: 2 additions & 0 deletions src/agent/agentContextLocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export function createContext(config: RunAgentConfig): AgentContext {
const hilBudget = config.humanInLoop?.budget ?? (process.env.HIL_BUDGET ? parseFloat(process.env.HIL_BUDGET) : 2);
const context: AgentContext = {
agentId: config.resumeAgentId || randomUUID(),
parentAgentId: config.parentAgentId,
executionId: randomUUID(),
childAgents: [],
traceId: '',
metadata: config.metadata ?? {},
name: config.agentName,
Expand Down
6 changes: 4 additions & 2 deletions src/agent/agentContextTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ export type AgentLLMs = Record<TaskLevel, LLM>;
export interface AgentContext {
/** Primary Key - Agent instance id. Allocated when the agent is first starts */
agentId: string;
/** Id of the running execution. This changes after the agent restarts due to an error, pausing, human in loop, etc */
/** Child agent ids */
childAgents?: string[];
/** Id of the running execution. This changes after the agent restarts due to an error, pausing, human in loop, completion etc */
executionId: string;
/** Current OpenTelemetry traceId */
traceId: string;
Expand Down Expand Up @@ -123,7 +125,7 @@ export interface AgentContext {
invoking: FunctionCall[];
/** Additional notes that tool functions can add to the response to the agent */
notes: string[];
/** The initial user prompt */
/** The initial prompt provided by the user or parent agent */
userPrompt: string;
/** The prompt the agent execution started/resumed with */
inputPrompt: string;
Expand Down
4 changes: 3 additions & 1 deletion src/agent/agentRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { logger } from '#o11y/logger';
import { User } from '#user/user';
import { errorToString } from '#utils/errors';
import { CDATA_END, CDATA_START } from '#utils/xml-utils';
import { appContext } from '../app';
import { appContext } from '../applicationContext';

export const SUPERVISOR_RESUMED_FUNCTION_NAME: string = `Supervisor${FUNC_SEP}Resumed`;
export const SUPERVISOR_CANCELLED_FUNCTION_NAME: string = `Supervisor${FUNC_SEP}Cancelled`;
Expand All @@ -22,6 +22,8 @@ const FUNCTION_OUTPUT_SUMMARIZE_MIN_LENGTH = 2000;
export interface RunAgentConfig {
/** The user who created the agent. Uses currentUser() if not provided */
user?: User;
/** The parent agentId */
parentAgentId?: string;
/** The name of this agent */
agentName: string;
/** The type of autonomous agent function calling. Defaults to codegen */
Expand Down
8 changes: 7 additions & 1 deletion src/agent/agentSerialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getCompletedHandler } from '#agent/completionHandlerRegistry';
import { FileSystemService } from '#functions/storage/fileSystemService';
import { deserializeLLMs } from '#llm/llmFactory';
import { currentUser } from '#user/userService/userContext';
import { appContext } from '../app';
import { appContext } from '../applicationContext';

export function serializeContext(context: AgentContext): Record<string, any> {
const serialized = {};
Expand All @@ -15,6 +15,10 @@ export function serializeContext(context: AgentContext): Record<string, any> {
} else if (context[key] === null) {
serialized[key] = null;
}
// Handle childAgents array specially to ensure it's always an array
else if (key === 'childAgents') {
serialized[key] = context[key] || [];
}
// Copy primitive properties across
else if (typeof context[key] === 'string' || typeof context[key] === 'number' || typeof context[key] === 'boolean') {
serialized[key] = context[key];
Expand Down Expand Up @@ -65,6 +69,7 @@ export async function deserializeAgentContext(serialized: Record<keyof AgentCont

context.memory = serialized.memory;
context.metadata = serialized.metadata;
context.childAgents = serialized.childAgents || [];
context.llms = deserializeLLMs(serialized.llms);

const user = currentUser();
Expand All @@ -79,6 +84,7 @@ export async function deserializeAgentContext(serialized: Record<keyof AgentCont
if (!context.iterations) context.iterations = 0;

// Need to default empty parameters. Seems to get lost in Firestore
context.functionCallHistory ??= [];
for (const call of context.functionCallHistory) call.parameters ??= {};

return context as AgentContext;
Expand Down
Loading
Loading