Skip to content

Commit edde4fc

Browse files
Refactor to reduce coupling between modules. Add agent parent/child p… (#38)
* Refactor to reduce coupling between modules. * Add agent parent/child properties. * Remove file based services
1 parent 6c83d5f commit edde4fc

File tree

82 files changed

+516
-601
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+516
-601
lines changed

CONVENTIONS.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,22 @@ Use async/await where possible
66

77
Test exceptional cases first and return/throw early.
88

9+
Never edit files name CONVENTIONS.md or .cursorrules
10+
11+
# Test code standards
12+
13+
Unit test files should be in the same directory as the source file.
14+
15+
Any usage of chai-as-promised should use async/await
16+
```
17+
it('should work well with async/await', async () => {
18+
(await Promise.resolve(42)).should.equal(42)
19+
await Promise.reject(new Error()).should.be.rejectedWith(Error);
20+
});
21+
```
22+
23+
# Tool/function classes
24+
25+
Function classes with the @funcClass(__filename) must only have the default constructor.
26+
27+
Always use the Filesystem class in src/functions/storage/filesystem.ts to read/search/write to the local filesystem.

frontend/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sophia/ui",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "Sophia AI platform",
55
"author": "https://themeforest.net/user/srcn, Daniel Campagnoli, TrafficGuard Pty Ltd, and contributors",
66
"license": "https://themeforest.net/licenses/standard",

package-lock.json

Lines changed: 20 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@trafficguard/sophia",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "AI agent & LLM app platform",
55
"private": true,
66
"type": "commonjs",
@@ -19,6 +19,7 @@
1919
"py": " node --env-file=variables/local.env -r ts-node/register src/cli/py.ts",
2020
"code": " node --env-file=variables/local.env -r ts-node/register src/cli/code.ts",
2121
"query": " node --env-file=variables/local.env -r ts-node/register src/cli/query.ts",
22+
"repos": " node --env-file=variables/local.env -r ts-node/register src/cli/repos.ts",
2223
"scrape": " node --env-file=variables/local.env -r ts-node/register src/cli/scrape.ts",
2324
"slack": " node --env-file=variables/local.env -r ts-node/register src/cli/slack.ts",
2425
"summarize": "node --env-file=variables/local.env -r ts-node/register src/cli/summarize.ts",
@@ -32,7 +33,6 @@
3233
"functionSchemas": "node --env-file=variables/local.env -r ts-node/register src/generateFunctionSchemas.ts",
3334
"start": " node -r ts-node/register src/index.ts",
3435
"start:local": "node -r ts-node/register --env-file=variables/local.env --inspect=0.0.0.0:9229 src/index.ts",
35-
"start:file": " node -r ts-node/register --env-file=variables/local.env src/index.ts --db=file",
3636
"emulators": "gcloud emulators firestore start --host-port=127.0.0.1:8243",
3737
"test": "npm run test:unit && echo \"No system or integration tests\"",
3838
"test:ci": "firebase emulators:exec --only firestore \"npm run test\"",
@@ -92,6 +92,7 @@
9292
"@types/axios": "^0.14.0",
9393
"@types/bcrypt": "^5.0.2",
9494
"@types/chai": "^4.3.16",
95+
"@types/micromatch": "^4.0.9",
9596
"@types/pg": "^8.11.4",
9697
"ai": "3.4.20",
9798
"api": "^6.1.1",
@@ -117,7 +118,7 @@
117118
"ignore": "^5.3.1",
118119
"jsdom": "^24.0.0",
119120
"lodash": "^4.17.20",
120-
"micromatch": "^4.0.7",
121+
"micromatch": "^4.0.8",
121122
"module-alias": "^2.2.2",
122123
"openai": "^4.28.4",
123124
"pino": "^8.18.0",

src/agent/LlmFunctions.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import { Agent } from '#agent/agentFunctions';
2+
import { functionFactory } from '#functionSchema/functionDecorators';
23
import { FUNC_SEP, FunctionSchema, getFunctionSchemas } from '#functionSchema/functions';
4+
import { FileSystemRead } from '#functions/storage/FileSystemRead';
5+
import { ToolType, toolType } from '#functions/toolType';
36
import { FunctionCall } from '#llm/llm';
47
import { logger } from '#o11y/logger';
58

6-
import { FileSystemService } from '#functions/storage/fileSystemService';
7-
import { GetToolType, ToolType, toolType } from '#functions/toolType';
8-
9-
import { functionFactory } from '#functionSchema/functionDecorators';
10-
import { FileSystemRead } from '#functions/storage/FileSystemRead';
11-
129
/**
1310
* Holds the instances of the classes with function callable methods.
1411
*/
@@ -28,6 +25,7 @@ export class LlmFunctions {
2825
}
2926

3027
fromJSON(obj: any): this {
28+
if (!obj) return this;
3129
const functionClassNames = (obj.functionClasses ?? obj.tools) as string[]; // obj.tools for backward compat with dev version
3230
for (const functionClassName of functionClassNames) {
3331
const ctor = functionFactory()[functionClassName];

src/agent/agentContext.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { deserializeAgentContext, serializeContext } from '#agent/agentSerializa
88
import { FileSystemRead } from '#functions/storage/FileSystemRead';
99
import { LlmTools } from '#functions/util';
1010
import { GPT4o } from '#llm/services/openai';
11-
import { appContext } from '../app';
11+
import { appContext } from '../applicationContext';
1212
import { functionRegistry } from '../functionRegistry';
1313

1414
describe('agentContext', () => {

src/agent/agentContextLocalStorage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ export function createContext(config: RunAgentConfig): AgentContext {
5353
const hilBudget = config.humanInLoop?.budget ?? (process.env.HIL_BUDGET ? parseFloat(process.env.HIL_BUDGET) : 2);
5454
const context: AgentContext = {
5555
agentId: config.resumeAgentId || randomUUID(),
56+
parentAgentId: config.parentAgentId,
5657
executionId: randomUUID(),
58+
childAgents: [],
5759
traceId: '',
5860
metadata: config.metadata ?? {},
5961
name: config.agentName,

src/agent/agentContextTypes.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ export type AgentLLMs = Record<TaskLevel, LLM>;
7070
export interface AgentContext {
7171
/** Primary Key - Agent instance id. Allocated when the agent is first starts */
7272
agentId: string;
73-
/** Id of the running execution. This changes after the agent restarts due to an error, pausing, human in loop, etc */
73+
/** Child agent ids */
74+
childAgents?: string[];
75+
/** Id of the running execution. This changes after the agent restarts due to an error, pausing, human in loop, completion etc */
7476
executionId: string;
7577
/** Current OpenTelemetry traceId */
7678
traceId: string;
@@ -123,7 +125,7 @@ export interface AgentContext {
123125
invoking: FunctionCall[];
124126
/** Additional notes that tool functions can add to the response to the agent */
125127
notes: string[];
126-
/** The initial user prompt */
128+
/** The initial prompt provided by the user or parent agent */
127129
userPrompt: string;
128130
/** The prompt the agent execution started/resumed with */
129131
inputPrompt: string;

src/agent/agentRunner.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { logger } from '#o11y/logger';
1010
import { User } from '#user/user';
1111
import { errorToString } from '#utils/errors';
1212
import { CDATA_END, CDATA_START } from '#utils/xml-utils';
13-
import { appContext } from '../app';
13+
import { appContext } from '../applicationContext';
1414

1515
export const SUPERVISOR_RESUMED_FUNCTION_NAME: string = `Supervisor${FUNC_SEP}Resumed`;
1616
export const SUPERVISOR_CANCELLED_FUNCTION_NAME: string = `Supervisor${FUNC_SEP}Cancelled`;
@@ -22,6 +22,8 @@ const FUNCTION_OUTPUT_SUMMARIZE_MIN_LENGTH = 2000;
2222
export interface RunAgentConfig {
2323
/** The user who created the agent. Uses currentUser() if not provided */
2424
user?: User;
25+
/** The parent agentId */
26+
parentAgentId?: string;
2527
/** The name of this agent */
2628
agentName: string;
2729
/** The type of autonomous agent function calling. Defaults to codegen */

src/agent/agentSerialization.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getCompletedHandler } from '#agent/completionHandlerRegistry';
44
import { FileSystemService } from '#functions/storage/fileSystemService';
55
import { deserializeLLMs } from '#llm/llmFactory';
66
import { currentUser } from '#user/userService/userContext';
7-
import { appContext } from '../app';
7+
import { appContext } from '../applicationContext';
88

99
export function serializeContext(context: AgentContext): Record<string, any> {
1010
const serialized = {};
@@ -15,6 +15,10 @@ export function serializeContext(context: AgentContext): Record<string, any> {
1515
} else if (context[key] === null) {
1616
serialized[key] = null;
1717
}
18+
// Handle childAgents array specially to ensure it's always an array
19+
else if (key === 'childAgents') {
20+
serialized[key] = context[key] || [];
21+
}
1822
// Copy primitive properties across
1923
else if (typeof context[key] === 'string' || typeof context[key] === 'number' || typeof context[key] === 'boolean') {
2024
serialized[key] = context[key];
@@ -65,6 +69,7 @@ export async function deserializeAgentContext(serialized: Record<keyof AgentCont
6569

6670
context.memory = serialized.memory;
6771
context.metadata = serialized.metadata;
72+
context.childAgents = serialized.childAgents || [];
6873
context.llms = deserializeLLMs(serialized.llms);
6974

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

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

8490
return context as AgentContext;

0 commit comments

Comments
 (0)