StanSava commited on
Commit
5df0d69
·
1 Parent(s): 654175d

switch to gemini model, update supabase_model managed agent query and update the flow (#10)

Browse files
.python-version CHANGED
@@ -1 +1 @@
1
- 3.11.6
 
1
+ 3.13
LLM/llm_models.py CHANGED
@@ -3,10 +3,18 @@ from .models import LLMProviderType, LLMModelType
3
  from .llm_provider import LLMProvider
4
 
5
 
6
- orchestrator_model = LLMProvider(LLMProviderType.HF, LLMModelType.open_source.deepseek_v3_terminus).get_model()
7
 
8
- supabase_model = LLMProvider(LLMProviderType.HF, LLMModelType.open_source.deepseek_v3_terminus).get_model()
9
- websearch_model = LLMProvider(LLMProviderType.HF, LLMModelType.open_source.qwen_80b_thinking).get_model()
 
 
 
 
 
 
 
 
10
 
11
  context_compression_model = LLMProvider(LLMProviderType.OPENAI, LLMModelType.openai.gpt_5_1).get_model()
12
  metaprompting_model = LLMProvider(LLMProviderType.OPENAI, LLMModelType.openai.gpt_5_1).get_model()
 
3
  from .llm_provider import LLMProvider
4
 
5
 
6
+ use_gemini = False
7
 
8
+ base_provider = LLMProviderType.GEMINI if use_gemini else LLMProviderType.HF
9
+
10
+ base_model = LLMModelType.gemini.gemini_2_5_pro if use_gemini else LLMModelType.open_source.deepseek_v3_terminus
11
+
12
+
13
+
14
+ orchestrator_model = LLMProvider(base_provider, base_model).get_model()
15
+
16
+ supabase_model = LLMProvider(base_provider, base_model).get_model()
17
+ websearch_model = LLMProvider(base_provider, base_model).get_model()
18
 
19
  context_compression_model = LLMProvider(LLMProviderType.OPENAI, LLMModelType.openai.gpt_5_1).get_model()
20
  metaprompting_model = LLMProvider(LLMProviderType.OPENAI, LLMModelType.openai.gpt_5_1).get_model()
LLM/models.py CHANGED
@@ -17,6 +17,7 @@ class AnthropicModel(str, Enum):
17
 
18
 
19
  class GeminiModel(str, Enum):
 
20
  gemini_2_5_flash = "gemini-2.5-flash"
21
  gemini_2_5_pro = "gemini-2.5-pro"
22
 
@@ -29,7 +30,7 @@ class OSSModel(str, Enum):
29
  deepseek_r1 = "deepseek-ai/DeepSeek-R1"
30
  gpt_oss_120b = "openai/gpt-oss-120b"
31
  kimi_k2_thinking = "moonshotai/Kimi-K2-Thinking",
32
- qwen_80b_thinking = 'Qwen/Qwen3-Next-80B-A3B-Thinking'
33
 
34
  class EnumNamespace:
35
  """Proxy to expose Enum members as attribute-accessed .value strings."""
 
17
 
18
 
19
  class GeminiModel(str, Enum):
20
+ gemini_3_pro_preview = "gemini-3-pro-preview"
21
  gemini_2_5_flash = "gemini-2.5-flash"
22
  gemini_2_5_pro = "gemini-2.5-pro"
23
 
 
30
  deepseek_r1 = "deepseek-ai/DeepSeek-R1"
31
  gpt_oss_120b = "openai/gpt-oss-120b"
32
  kimi_k2_thinking = "moonshotai/Kimi-K2-Thinking",
33
+ qwen_3_coder = 'Qwen/Qwen3-Coder-480B-A35B-Instruct'
34
 
35
  class EnumNamespace:
36
  """Proxy to expose Enum members as attribute-accessed .value strings."""
UI/render_employee_card.py CHANGED
@@ -17,7 +17,8 @@ def _as_mapping(member: EmployeeTrainingPlan | Mapping[str, Any]) -> Mapping[str
17
  if hasattr(member, "model_dump"):
18
  return member.model_dump()
19
  return {
20
- "employee_id": getattr(member, "employee_id", "Unknown employee"),
 
21
  "skills_gaps": getattr(member, "skills_gaps", []),
22
  "training_plan": getattr(member, "training_plan", []),
23
  }
@@ -108,7 +109,7 @@ def _render_training_plan(resources: Iterable[Mapping[str, Any]] | None) -> str:
108
 
109
  def render_employee_card(member: EmployeeTrainingPlan | Mapping[str, Any]) -> str:
110
  data = _as_mapping(member)
111
- name = html.escape(str(data.get("employee_id", "Unknown employee")))
112
  role = html.escape(str(data.get("role") or "Not provided"))
113
 
114
  skill_gap_html = _render_skill_gaps(data.get("skills_gaps"))
 
17
  if hasattr(member, "model_dump"):
18
  return member.model_dump()
19
  return {
20
+ "employee_name": getattr(member, "employee_name", "Unknown employee"),
21
+ "role": getattr(member, "role", "Unknown role"),
22
  "skills_gaps": getattr(member, "skills_gaps", []),
23
  "training_plan": getattr(member, "training_plan", []),
24
  }
 
109
 
110
  def render_employee_card(member: EmployeeTrainingPlan | Mapping[str, Any]) -> str:
111
  data = _as_mapping(member)
112
+ name = html.escape(str(data.get("employee_name", "Unknown employee")))
113
  role = html.escape(str(data.get("role") or "Not provided"))
114
 
115
  skill_gap_html = _render_skill_gaps(data.get("skills_gaps"))
agents/orchestrator_agent/orchestrator_agent.py CHANGED
@@ -19,7 +19,7 @@ metaprompting_agent = MetapromptingAgent()
19
  SUGGEST_METAPROMPT_IMPROVEMENTS = False
20
 
21
  @tool
22
- def final_answer_callback(project_id: str, project_name: str, budget:int, deadline: str, status: str, team: List[EmployeeTrainingPlan]) -> AnalysisResult:
23
  """
24
  Finalizes the training-plan analysis and hands structured data back to the app about the project, the team and the training plan.
25
  ⚠️ This MUST be the last call. Do not call it before all skill gaps and training items are collected.
 
19
  SUGGEST_METAPROMPT_IMPROVEMENTS = False
20
 
21
  @tool
22
+ def final_answer_callback(project_id: int, project_name: str, budget:int, deadline: str, status: str, team: List[EmployeeTrainingPlan]) -> AnalysisResult:
23
  """
24
  Finalizes the training-plan analysis and hands structured data back to the app about the project, the team and the training plan.
25
  ⚠️ This MUST be the last call. Do not call it before all skill gaps and training items are collected.
agents/supabase_agent/get_supabase_agent_prompt.py CHANGED
@@ -62,6 +62,8 @@ Each returns:
62
 
63
  Therefore: NEVER recompute gap logic client-side unless strictly necessary.
64
 
 
 
65
  ────────────────────────────────────
66
  WHEN TO SUGGEST NEW RPC
67
  ────────────────────────────────────
 
62
 
63
  Therefore: NEVER recompute gap logic client-side unless strictly necessary.
64
 
65
+ When executing a function, execute it like this: execute_sql(query=.....), don't pass the query directly, use keyword args.
66
+
67
  ────────────────────────────────────
68
  WHEN TO SUGGEST NEW RPC
69
  ────────────────────────────────────
agents/websearch_agent/get_web_search_agent.py CHANGED
@@ -1,5 +1,5 @@
1
 
2
- from smolagents import ToolCallingAgent, WebSearchTool
3
 
4
  from LLM.llm_models import websearch_model
5
 
@@ -12,7 +12,7 @@ def get_web_search_agent(step_callbacks):
12
  if _web_search_agent is None:
13
  _web_search_agent = ToolCallingAgent(
14
  model=websearch_model,
15
- tools=[WebSearchTool()],
16
  step_callbacks=step_callbacks,
17
  name="web_search_agent",
18
  description="An agent that searches for relevant online courses, certifications, and learning paths."
 
1
 
2
+ from smolagents import ToolCallingAgent, DuckDuckGoSearchTool
3
 
4
  from LLM.llm_models import websearch_model
5
 
 
12
  if _web_search_agent is None:
13
  _web_search_agent = ToolCallingAgent(
14
  model=websearch_model,
15
+ tools=[DuckDuckGoSearchTool()],
16
  step_callbacks=step_callbacks,
17
  name="web_search_agent",
18
  description="An agent that searches for relevant online courses, certifications, and learning paths."
mcp_server/server.py DELETED
@@ -1,25 +0,0 @@
1
- from fastmcp import FastMCP
2
- from fastmcp.tools import Tool
3
-
4
- mcp = FastMCP('mcp_server')
5
- # Minimal MCP stdio server skeleton
6
- from .tools import (
7
- get_team_members,
8
- get_employees_skills,
9
- get_project_requirements,
10
- search_training_materials,
11
- save_training_plan,
12
- get_training_plans,
13
- )
14
- mcp.add_tool(Tool.from_function(get_team_members))
15
- mcp.add_tool(Tool.from_function(get_employees_skills))
16
- mcp.add_tool(Tool.from_function(get_project_requirements))
17
- mcp.add_tool(Tool.from_function(search_training_materials))
18
- mcp.add_tool(Tool.from_function(save_training_plan))
19
- mcp.add_tool(Tool.from_function(get_training_plans))
20
- def main():
21
- # Placeholder for stdio server loop
22
- mcp.run()
23
-
24
- if __name__ == "__main__":
25
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mcp_server/tools.py DELETED
@@ -1,21 +0,0 @@
1
- from typing import List, Dict, Any
2
- from models import TrainingPlan
3
-
4
-
5
- def get_team_members(project_id: str) -> List[str]:
6
- raise NotImplementedError("Implement this later")
7
-
8
- def get_employees_skills(employee_ids: List[str]) -> Dict[str, Dict[str, int]]:
9
- raise NotImplementedError("Implement this later")
10
-
11
- def get_project_requirements(project_id: str) -> Dict[str, int]:
12
- raise NotImplementedError("Implement this later")
13
-
14
- def save_training_plan(training_plan: TrainingPlan) -> None:
15
- raise NotImplementedError("Implement this later")
16
-
17
- def get_training_plans(project_id: str) -> List[TrainingPlan]:
18
- raise NotImplementedError("Implement this later")
19
-
20
-
21
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models.py CHANGED
@@ -1,21 +1,20 @@
1
  from __future__ import annotations
2
  from pydantic import BaseModel
3
- from typing import List, Dict, Optional
4
- from datetime import datetime
5
 
6
  class Employee(BaseModel):
7
  id: str
8
  name: str
9
- role: str
10
- skills: Dict[str, int] # skill name -> proficiency (0-100)
 
 
 
11
 
12
  class EmployeeSkillGap(BaseModel):
13
  employee_id: str
14
  skill: str
15
 
16
- class ProjectRequirement(BaseModel):
17
- project_id: str
18
- required_skills: Dict[str, int] # skill -> desired proficiency
19
 
20
  class TrainingMaterial(BaseModel):
21
  id: str
@@ -25,16 +24,8 @@ class TrainingMaterial(BaseModel):
25
  cost: Optional[float] = None
26
  duration_hours: Optional[float] = None
27
 
28
- class TrainingPlan(BaseModel):
29
- id: Optional[str] = None
30
- project_id: str
31
- employees: List[str]
32
- recommended_materials: Dict[str, List[TrainingMaterial]]
33
- total_cost: Optional[float] = None
34
- created_at: Optional[datetime] = None
35
-
36
  class EmployeeTrainingPlan(BaseModel):
37
- employee_id: str
38
  role: str
39
  skills_gaps: List[EmployeeSkillGap]
40
  training_plan: List[TrainingMaterial]
 
1
  from __future__ import annotations
2
  from pydantic import BaseModel
3
+ from typing import List, Optional
 
4
 
5
  class Employee(BaseModel):
6
  id: str
7
  name: str
8
+ role: str
9
+ department: str
10
+ level: str
11
+ project_id: List[str]
12
+ hourly_rate: Optional[float] = None
13
 
14
  class EmployeeSkillGap(BaseModel):
15
  employee_id: str
16
  skill: str
17
 
 
 
 
18
 
19
  class TrainingMaterial(BaseModel):
20
  id: str
 
24
  cost: Optional[float] = None
25
  duration_hours: Optional[float] = None
26
 
 
 
 
 
 
 
 
 
27
  class EmployeeTrainingPlan(BaseModel):
28
+ employee_name: str
29
  role: str
30
  skills_gaps: List[EmployeeSkillGap]
31
  training_plan: List[TrainingMaterial]
pyproject.toml CHANGED
@@ -6,7 +6,7 @@ version = "0.1.0"
6
  description = "SmolAgents-based HR skill-gap analysis and training planner app (EastSync)"
7
  authors = ["EastSync Team"]
8
  readme = "README.md"
9
- requires-python = ">=3.10"
10
  dependencies = [
11
  "pydantic>=2.0.0",
12
  "gradio==6.0.0.dev1",
@@ -15,6 +15,7 @@ dependencies = [
15
  "fastmcp>=2.13.1",
16
  "ddgs>=9.9.1",
17
  "repr>=0.3.1",
 
18
  ]
19
 
20
  [tool.uv]
 
6
  description = "SmolAgents-based HR skill-gap analysis and training planner app (EastSync)"
7
  authors = ["EastSync Team"]
8
  readme = "README.md"
9
+ requires-python = ">=3.13"
10
  dependencies = [
11
  "pydantic>=2.0.0",
12
  "gradio==6.0.0.dev1",
 
15
  "fastmcp>=2.13.1",
16
  "ddgs>=9.9.1",
17
  "repr>=0.3.1",
18
+ "typer>=0.20.0",
19
  ]
20
 
21
  [tool.uv]
response_sample.json CHANGED
@@ -1,163 +1,143 @@
1
  {
2
- "project_id":"2",
3
- "project_name":"Cloud Migration Initiative",
4
- "budget":180000,
5
- "deadline":"2025-07-01",
6
- "status":"Ongoing",
7
- "team":[
8
- {
9
- "employee_id":"4",
10
- "role":"DevOps Engineer",
11
- "skills_gaps":[
12
-
13
- ],
14
- "training_plan":[
15
-
16
- ]
17
- },
18
- {
19
- "employee_id":"5",
20
- "role":"Cloud Engineer",
21
- "skills_gaps":[
22
- {
23
- "employee_id":"5",
24
- "skill":"Terraform"
25
- }
26
- ],
27
- "training_plan":[
28
- {
29
- "id":"terraform_1",
30
- "title":"HashiCorp Terraform Associate Certification",
31
- "url":"https://developer.hashicorp.com/certifications",
32
- "skills_covered":[
33
- "Terraform"
34
- ],
35
- "cost":100.0,
36
- "duration_hours":20.0
37
- }
38
- ]
39
- },
40
- {
41
- "employee_id":"6",
42
- "role":"Java Engineer",
43
- "skills_gaps":[
44
- {
45
- "employee_id":"6",
46
- "skill":"AWS"
47
- },
48
- {
49
- "employee_id":"6",
50
- "skill":"Docker"
51
- },
52
- {
53
- "employee_id":"6",
54
- "skill":"Terraform"
55
- }
56
- ],
57
- "training_plan":[
58
- {
59
- "id":"aws_1",
60
- "title":"AWS Skill Builder (Free Courses)",
61
- "url":"https://skillbuilder.aws",
62
- "skills_covered":[
63
- "AWS"
64
- ],
65
- "cost":0.0,
66
- "duration_hours":25.0
67
- },
68
- {
69
- "id":"docker_2",
70
- "title":"Coursera Docker Specialization",
71
- "url":"https://www.coursera.org/courses?query=docker",
72
- "skills_covered":[
73
- "Docker"
74
- ],
75
- "cost":49.0,
76
- "duration_hours":40.0
77
- },
78
- {
79
- "id":"terraform_2",
80
- "title":"Coursera Terraform Courses",
81
- "url":"https://www.coursera.org/courses?query=terraform",
82
- "skills_covered":[
83
- "Terraform"
84
- ],
85
- "cost":49.0,
86
- "duration_hours":30.0
87
- }
88
- ]
89
- },
90
- {
91
- "employee_id":"19",
92
- "role":"Software Engineer",
93
- "skills_gaps":[
94
- {
95
- "employee_id":"19",
96
- "skill":"AWS"
97
- },
98
- {
99
- "employee_id":"19",
100
- "skill":"Docker"
101
- },
102
- {
103
- "employee_id":"19",
104
- "skill":"Terraform"
105
- }
106
- ],
107
- "training_plan":[
108
- {
109
- "id":"aws_3",
110
- "title":"AWS Solutions Architect - Associate",
111
- "url":"https://aws.amazon.com/training/",
112
- "skills_covered":[
113
- "AWS"
114
- ],
115
- "cost":150.0,
116
- "duration_hours":40.0
117
- },
118
- {
119
- "id":"docker_1",
120
- "title":"Docker Certified Associate (DCA) Preparation by ONLC",
121
- "url":"https://www.onlc.com/docker-training-classes.htm",
122
- "skills_covered":[
123
- "Docker"
124
- ],
125
- "cost":2000.0,
126
- "duration_hours":32.0
127
- },
128
- {
129
- "id":"terraform_3",
130
- "title":"Edstellar Terraform CorporateTraining",
131
- "url":"https://www.edstellar.com/course/terraform-training",
132
- "skills_covered":[
133
- "Terraform"
134
- ],
135
- "cost":2000.0,
136
- "duration_hours":20.0
137
- }
138
- ]
139
- },
140
- {
141
- "employee_id":"20",
142
- "role":"Cloud Architect",
143
- "skills_gaps":[
144
- {
145
- "employee_id":"20",
146
- "skill":"Docker"
147
- }
148
- ],
149
- "training_plan":[
150
- {
151
- "id":"docker_1",
152
- "title":"Docker Certified Associate (DCA) Preparation by ONLC",
153
- "url":"https://www.onlc.com/docker-training-classes.htm",
154
- "skills_covered":[
155
- "Docker"
156
- ],
157
- "cost":2000.0,
158
- "duration_hours":32.0
159
- }
160
- ]
161
- }
162
- ]
163
  }
 
1
  {
2
+ "project_id": 2,
3
+ "project_name": "Cloud Migration Initiative",
4
+ "budget": 180000,
5
+ "deadline": "2025-07-01",
6
+ "status": "Ongoing",
7
+ "team": [
8
+ {
9
+ "employee_name": "Emily Davis",
10
+ "role": "DevOps Engineer",
11
+ "skills_gaps": [],
12
+ "training_plan": []
13
+ },
14
+ {
15
+ "employee_name": "Michael Brown",
16
+ "role": "Cloud Engineer",
17
+ "skills_gaps": [
18
+ { "skill": "Terraform" }
19
+ ],
20
+ "training_plan": [
21
+ {
22
+ "id": "T01",
23
+ "title": "Terraform Online Training and Certification Course",
24
+ "url": "https://secappslearning.com/course/terraform-online-training-and-certification-course",
25
+ "skills_covered": ["Terraform"],
26
+ "cost": 24999,
27
+ "duration_hours": 35
28
+ }
29
+ ]
30
+ },
31
+ {
32
+ "employee_name": "Daniel Wilson",
33
+ "role": "Java Engineer",
34
+ "skills_gaps": [
35
+ { "skill": "AWS" },
36
+ { "skill": "Docker" },
37
+ { "skill": "Terraform" }
38
+ ],
39
+ "training_plan": [
40
+ {
41
+ "id": "A01",
42
+ "title": "AWS Training and Certification",
43
+ "url": "https://mindmajix.com/aws-training",
44
+ "skills_covered": ["AWS"],
45
+ "cost": 0,
46
+ "duration_hours": 25
47
+ },
48
+ {
49
+ "id": "D01",
50
+ "title": "Docker for the Absolute Beginner",
51
+ "url": "https://www.coursera.org/learn/docker-for-the-absolute-beginner",
52
+ "skills_covered": ["Docker"],
53
+ "cost": 0,
54
+ "duration_hours": 16
55
+ },
56
+ {
57
+ "id": "D02",
58
+ "title": "Docker - Introducing Docker Essentials, Containers, and more",
59
+ "url": "https://www.udemy.com/course/docker-introducing-docker-essentials-containers-and-more/",
60
+ "skills_covered": ["Docker"],
61
+ "cost": 0,
62
+ "duration_hours": 2.5
63
+ },
64
+ {
65
+ "id": "T01",
66
+ "title": "Terraform Online Training and Certification Course",
67
+ "url": "https://secappslearning.com/course/terraform-online-training-and-certification-course",
68
+ "skills_covered": ["Terraform"],
69
+ "cost": 24999,
70
+ "duration_hours": 35
71
+ }
72
+ ]
73
+ },
74
+ {
75
+ "employee_name": "Jacob Collins",
76
+ "role": "Software Engineer",
77
+ "skills_gaps": [
78
+ { "skill": "AWS" },
79
+ { "skill": "Docker" },
80
+ { "skill": "Terraform" }
81
+ ],
82
+ "training_plan": [
83
+ {
84
+ "id": "A01",
85
+ "title": "AWS Training and Certification",
86
+ "url": "https://mindmajix.com/aws-training",
87
+ "skills_covered": ["AWS"],
88
+ "cost": 0,
89
+ "duration_hours": 25
90
+ },
91
+ {
92
+ "id": "D01",
93
+ "title": "Docker for the Absolute Beginner",
94
+ "url": "https://www.coursera.org/learn/docker-for-the-absolute-beginner",
95
+ "skills_covered": ["Docker"],
96
+ "cost": 0,
97
+ "duration_hours": 16
98
+ },
99
+ {
100
+ "id": "D02",
101
+ "title": "Docker - Introducing Docker Essentials, Containers, and more",
102
+ "url": "https://www.udemy.com/course/docker-introducing-docker-essentials-containers-and-more/",
103
+ "skills_covered": ["Docker"],
104
+ "cost": 0,
105
+ "duration_hours": 2.5
106
+ },
107
+ {
108
+ "id": "T01",
109
+ "title": "Terraform Online Training and Certification Course",
110
+ "url": "https://secappslearning.com/course/terraform-online-training-and-certification-course",
111
+ "skills_covered": ["Terraform"],
112
+ "cost": 24999,
113
+ "duration_hours": 35
114
+ }
115
+ ]
116
+ },
117
+ {
118
+ "employee_name": "Chloe Morgan",
119
+ "role": "Cloud Architect",
120
+ "skills_gaps": [
121
+ { "skill": "Docker" }
122
+ ],
123
+ "training_plan": [
124
+ {
125
+ "id": "D01",
126
+ "title": "Docker for the Absolute Beginner",
127
+ "url": "https://www.coursera.org/learn/docker-for-the-absolute-beginner",
128
+ "skills_covered": ["Docker"],
129
+ "cost": 0,
130
+ "duration_hours": 16
131
+ },
132
+ {
133
+ "id": "D02",
134
+ "title": "Docker - Introducing Docker Essentials, Containers, and more",
135
+ "url": "https://www.udemy.com/course/docker-introducing-docker-essentials-containers-and-more/",
136
+ "skills_covered": ["Docker"],
137
+ "cost": 0,
138
+ "duration_hours": 2.5
139
+ }
140
+ ]
141
+ }
142
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
uv.lock CHANGED
The diff for this file is too large to render. See raw diff