Skip to content

Commit 75c7225

Browse files
authored
feat(core): add previous task infos for SOP extraction (#33)
* fix(core): set true at the end of space agent * feat(core): add previous task context to sop agent * fix(core): sop with condidtion * prompt(core): use sop agent * prompt: update task tracking * feat(core): update learning status api * test: update learning status
1 parent 2cb86f2 commit 75c7225

File tree

14 files changed

+138
-42
lines changed

14 files changed

+138
-42
lines changed

src/server/core/acontext_core/llm/agent/space_construct.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from ...schema.utils import asUUID
1111
from ..prompt.space_construct import SpaceConstructPrompt
1212
from ..tool.space_tools import SPACE_TOOLS, SpaceCtx
13+
from ..tool.space_lib.insert_candidate_data_as_content import set_space_digests
1314

1415

1516
async def build_space_ctx(
@@ -76,12 +77,13 @@ async def space_construct_agent_curd(
7677
}
7778
for sop_data in sop_datas
7879
]
80+
candidate_data_section = pack_candidate_data_list(candidate_data_list)
81+
LOG.info(f"Candidate Data Section: {candidate_data_section}")
82+
7983
_messages = [
8084
{
8185
"role": "user",
82-
"content": SpaceConstructPrompt.pack_task_input(
83-
pack_candidate_data_list(candidate_data_list)
84-
),
86+
"content": SpaceConstructPrompt.pack_task_input(candidate_data_section),
8587
}
8688
]
8789
just_finish = False
@@ -143,4 +145,16 @@ async def space_construct_agent_curd(
143145
LOG.info("finish tool called, exit the loop")
144146
break
145147
already_iterations += 1
148+
149+
async with DB_CLIENT.get_session_context() as db_session:
150+
USE_CTX = await build_space_ctx(
151+
db_session,
152+
project_id,
153+
space_id,
154+
task_ids,
155+
candidate_data_list,
156+
before_use_ctx=USE_CTX,
157+
)
158+
for d_i in USE_CTX.already_inserted_candidate_data:
159+
await set_space_digests(USE_CTX, d_i)
146160
return Result.resolve(None)

src/server/core/acontext_core/llm/agent/task.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ async def task_agent_curd(
134134

135135
LOG.info(f"Task Section: {task_section}")
136136
LOG.info(f"Previous Progress Section: {previous_progress_section}")
137-
LOG.info(f"Current Messages Section: {current_messages_section}")
138137

139138
json_tools = [tool.model_dump() for tool in TaskPrompt.tool_schema()]
140139
already_iterations = 0

src/server/core/acontext_core/llm/agent/task_sop.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import Optional, List
22
from ...env import LOG, bound_logging_vars
33
from ...schema.result import Result
44
from ...schema.utils import asUUID
@@ -25,21 +25,45 @@ def pack_task_data(
2525
)
2626

2727

28+
def pack_one_task_progress_context(task: TaskSchema) -> str:
29+
progresses = task.data.progresses or []
30+
progress_context = "\n".join([f"- {p}" for p in progresses])
31+
return f"""<task id={task.order}>
32+
Description: {task.data.task_description}
33+
Progresses:
34+
{progress_context}
35+
</task>
36+
"""
37+
38+
39+
def pack_previous_task_context(
40+
previous_tasks: List[TaskSchema], current_task: TaskSchema
41+
) -> str:
42+
prev_tasks = "\n".join(
43+
[pack_one_task_progress_context(task) for task in previous_tasks]
44+
)
45+
return f"""{prev_tasks}
46+
You're looking at task {current_task.order}.
47+
"""
48+
49+
2850
@track_process
2951
async def sop_agent_curd(
3052
project_id: asUUID,
3153
space_id: asUUID,
3254
current_task: TaskSchema,
55+
previous_tasks: List[TaskSchema],
3356
message_blobs: list[MessageBlob],
3457
max_iterations=3,
3558
project_config: Optional[ProjectConfig] = None,
3659
):
37-
3860
task_desc, user_perferences, raw_messages = pack_task_data(
3961
current_task, message_blobs
4062
)
63+
previous_task_context = pack_previous_task_context(previous_tasks, current_task)
4164

42-
LOG.info(f"Task SOP before: {task_desc}, {user_perferences}, {raw_messages}")
65+
LOG.info(f"Task SOP Input: {task_desc}, {user_perferences}")
66+
LOG.info(f"Previous Task Context: {previous_task_context}")
4367

4468
# Build customization from project config
4569
customization = None
@@ -55,7 +79,7 @@ async def sop_agent_curd(
5579
{
5680
"role": "user",
5781
"content": TaskSOPPrompt.pack_task_input(
58-
task_desc, user_perferences, raw_messages
82+
previous_task_context, task_desc, user_perferences, raw_messages
5983
),
6084
}
6185
]

src/server/core/acontext_core/llm/prompt/task.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,11 @@ def system_prompt(cls) -> str:
4949
- If user mentioned any preference on this task, extract in the clean format 'user expects/wants...' in 'user_preference_and_infos' field.
5050
- If user mentioned any infos(address, email,... etc) so that the task can be completed, extract it and fill it in 'user_preference_and_infos' field.
5151
52-
## Append with Progress
53-
- Give a brief progress of the task when appending messages
54-
- Concise and short. only state what the current state.
52+
## Summary the Task State and Append to Progress
53+
- Give a concise current state of the task when appending messages
5554
- Narrate progress in the first person as the agent.
5655
- Facts over General. Don't say "I encountered many errors", say "I encountered python syntax and rust compiling error."
57-
- Actual State over Reference. Don't say 'I open the target websit', say "I navigate to https://github.com/trending".
56+
- Actual Value over Generic. Don't say 'I open the target websit', say "I navigate to https://github.com/trending". Use actual website url, DB table... when possible.
5857
5958
## Update Task Status
6059
- `pending`: For tasks not yet started
@@ -79,14 +78,14 @@ def system_prompt(cls) -> str:
7978
2. Does the user report that any task failed and need to re-run?
8079
3. How existing tasks are related to current conversation?
8180
4. Any new task should be created?
82-
5. Which Messages are contributed to planning? Not the execution.
81+
5. Which Messages are contributed to planning?
8382
6. Which Messages are contributed to which task? What the progress of the messages brough to the task?
8483
7. Any user preferences and personal infos in Current Message section related to complete which tasks?
85-
8. Any progress should be appended with actual states?
84+
8. What's the actual value for state should be appended to progress?
8685
9. Which task's status need to be updated?
8786
10. Briefly describe your tool-call actions to correctly manage the tasks.
8887
89-
Call 'finish' tool if you have finish your jobs.
88+
Before call 'finish' tool to quit, report your thinking again to make sure every action is covered, if not, continue to perform your job then 'finish'
9089
"""
9190

9291
@classmethod

src/server/core/acontext_core/llm/prompt/task_sop.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ def system_prompt(
1919
Complete system prompt string
2020
"""
2121
# Build base scoring rules
22-
base_scoring_section = """### Task Complexity Scoring
23-
(c.1) If there're errors because of the wrong tool parameter passing and it can be avoided, + 1 point
22+
base_scoring_section = """(c.1) If there're errors because of the wrong tool parameter passing and it can be avoided, + 1 point
2423
(c.2) If there're back-and-forth retries (not errors) because agent has a wrong strategy, + 1 point.
2524
(c.3) If agent done something wrong decision before, then user offers some feedbacks/preferences to correct the agent's wrong decision, + 2 points
26-
(c.4) User explicitly emphasized saving this workflow or experience, + 5 points"""
25+
(c.4) User explicitly emphasized to remember during the task, + 2 points"""
2726

2827
# Append custom scoring rules if provided
2928
if customization and customization.custom_scoring_rules:
@@ -41,37 +40,50 @@ def system_prompt(
4140
return f"""You're a Tool-calling SOP Agent that analyzes user-agent working history and generates reusable tool-calling SOPs.
4241
4342
## Core Responsibilities
44-
- Understand task and user preferences
43+
- Understand task conditions and user preferences
4544
- Give the task's complexity a score.
4645
- Skip easy task's tool_sop, or abstract a template SOP from complex task.
46+
47+
## Task Complexity Scoring
4748
{base_scoring_section}
4849
If a task's complexity score is < 2, then skip the task because it's too easy, and you should submit a empty SOP with `is_easy_task` set to True.
4950
else, set `is_easy_task` to False.
5051
51-
### Tool-calling SOP Abstraction
52+
## Tool-calling SOP Abstraction
5253
If the task is not an easy task, abstract a template SOP from complex task for a certain scenario, using 'submit_sop' tool:
5354
- When generate `tool_sops`, use the exact tool_name from <agent_action>, and keep the most necessary and generalizable arguments in 'action'.
5455
- `tool_sops` can be an empty list if the task itself is a easy task.
5556
- If this task involves the same workflow repeated with different inputs, only retain the most concise SOP from a single iteration.
56-
#### Templatized Tool Action
57+
### Templatized Tool Action
5758
- Template SOP must be the shortest possible too-calls to achieve the goal, remove all the redundancies.
5859
- Template tool sops: remove those parameters that may vary in different user input in tool 'action', only keep the parameters that are critical to the sop case.
5960
For example, if the sop is 'star a github repo',
6061
then the detailed repo url should be removed because next time user may input a new repo url.
6162
But use `click` tool to click a 'Star' button, this can keep in action because the 'Star' button is a universal step and unrelated to the user's input.
62-
#### Preferences
63-
- remove those preferences or infos that are may vary in different user input.
63+
### Preferences
64+
- remove those preferences or infos that are may vary in the future input.
65+
- keep those preferences and infos that are critical to the future SOP execution.
66+
67+
## Find the conditions of the Current Task
68+
- Current Task is only possible when bounded to certain conditions. For example:
69+
- the sop is about starring a repo, the inferred conditions is agent is on github.com so that agent can star a repo, the use_when should be 'star a repo on github.com', not 'star a repo'.
70+
- the sop is about querying by certain year, the inferred conditions is in private_lung_cancer table so that SQL query is only valid, the use_when should be 'query private_lung_cancer table by certain year', not 'query by certain year'.
71+
- You must infer the conditions of the current task from the previous tasks context and working history.
72+
- Conditions must be concrete: 'on github.com' is better than 'on code website', 'on private_lung_cancer MySQL table' is better than 'on a cancer table'.
73+
- You must include the conditions in the SOP's `use_when` field: 'star a repo on github.com', 'query private_lung_cancer table by certain year'.
6474
6575
## Input Format
76+
### Previous Task Context
77+
This section contains the previous tasks progresses.
78+
Make sure your understand the state of the current task (e.g. which website the agent is on, which db table the agent is querying, etc.)
6679
### Task Description
6780
What the task is and its purpose.
6881
### User Preferences and Infos
69-
User preferences and personal infos for this task.
82+
User preferences and personal infos extracted from this task.
7083
### Raw Working History
7184
Format:
7285
```
7386
<user>(text) ...
74-
<agent>(text) ...
7587
<agent>(tool-call) 'tool_name': '...', 'arguments': '...'
7688
<agent>(tool-result) 'tool_name': '...', 'result': '...'
7789
```
@@ -81,21 +93,28 @@ def system_prompt(
8193
## Report before Submit
8294
You must report your thinkings (using extrmaly brief wordings) first using the 'report_thinking' tool:
8395
1. What's tools have been used?
84-
2. Give your judgement on {rule_indices_str} and for each term, what's the scores?, then sum them and score the task complexity.
85-
3. If it's an easy task, confirm you will set `is_easy_task` to True and only submit the `use_when` and `preferences` field and an empty `tool_sops list
86-
4. How to reduce the tool-calls to build a shortest path to achieve the goal?
87-
5. Which parameters/values are related to the future user input and should be removed in 'action' and 'preferences'?
88-
6. Which parameters/values are necessary to make sure the SOP will have no more unexpected errors and back-and-forth retries?
89-
7. In which general scenarios should we use this SOP? (3~5 words for `use_when`)
90-
8. Any user preferences can help this general scenarios? (short sentenqces for `preferences`) If not, 'preferences' field should be empty string
96+
2. Infer the necessary conditions for the Current Task can happened.
97+
3. Give your judgement on {rule_indices_str} and for each term, what's the scores?, then sum them and score the task complexity.
98+
4. If it's an easy task, confirm you will set `is_easy_task` to True and only submit and with an empty `tool_sops list
99+
5. How to reduce the tool-calls to build a shortest path to achieve the goal?
100+
6. Which parameters/values are related to the future user input and should be removed in 'action' and 'preferences'?
101+
7. Which parameters/values are necessary to make sure the SOP will have no more unexpected errors and back-and-forth retries?
102+
8. When and with which condidtions should we apply this SOP? (for `use_when`)?
103+
9. Any user preferences to keep for future SOP execution? (for `preferences`) If not, 'preferences' field should be empty string
91104
Then decide if you should submit the SOP.
92105
"""
93106

94107
@classmethod
95108
def pack_task_input(
96-
cls, task_description: str, user_preferences: str, history_messages: str
109+
cls,
110+
previous_task_context: str,
111+
task_description: str,
112+
user_preferences: str,
113+
history_messages: str,
97114
) -> str:
98-
return f"""### Task Description
115+
return f"""### Previous Task Context
116+
{previous_task_context}
117+
### Current Task Description
99118
{task_description}
100119
### User Preferences and Infos
101120
{user_preferences}

src/server/core/acontext_core/llm/tool/space_lib/insert_candidate_data_as_content.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ async def _insert_data_handler(
4848
)
4949
if not r.ok():
5050
return Result.resolve(f"Failed to insert candidate data: {r.error}")
51-
await set_space_digests(ctx, candidate_index)
5251
return Result.resolve(
5352
f"Inserted candidate data {candidate_index} to page {page_path} after block index {after_block_index}"
5453
)

src/server/core/acontext_core/schema/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ class ProjectConfig(BaseModel):
1616
project_session_message_buffer_max_turns: int = 16
1717
project_session_message_buffer_max_overflow: int = 16
1818
project_session_message_buffer_ttl_seconds: int = 8 # 4 seconds
19-
default_task_agent_max_iterations: int = 4
19+
default_task_agent_max_iterations: int = 6
2020
default_task_agent_previous_progress_num: int = 6
2121
default_sop_agent_max_iterations: int = 4
2222
default_space_construct_agent_max_iterations: int = 16
23+
default_space_construct_agent_previous_tasks_limit: int = 5
2324

2425
# SOP Agent Customization (extensible for future features)
2526
sop_agent_custom_scoring_rules: List[CustomScoringRule] = []

src/server/core/acontext_core/schema/mq/sop.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from pydantic import BaseModel
22
from ..utils import asUUID
33
from ..block.sop_block import SOPData
4-
from typing import Dict, Any
54

65

76
class SOPComplete(BaseModel):

src/server/core/acontext_core/service/controller/space_sop.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ async def process_sop_complete(
1616
Process SOP completion and trigger construct agent
1717
"""
1818
LOG.info(f"Processing SOP completion for task {task_id}")
19-
2019
# Call construct agent
2120
construct_result = await SC.space_construct_agent_curd(
2221
project_id,

src/server/core/acontext_core/service/controller/space_task.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ...env import LOG
88
from ...schema.config import ProjectConfig
99
from ...schema.session.task import TaskSchema
10+
from ..data import task as TD
1011

1112

1213
async def process_space_task(
@@ -31,10 +32,22 @@ async def process_space_task(
3132
MessageBlob(message_id=m.id, role=m.role, parts=m.parts, task_id=m.task_id)
3233
for m in messages
3334
]
34-
r = await TSOP.sop_agent_curd(
35+
async with DB_CLIENT.get_session_context() as db_session:
36+
r = await TD.fetch_previous_tasks_without_message_ids(
37+
db_session,
38+
task.session_id,
39+
st_order=task.order,
40+
limit=project_config.default_space_construct_agent_previous_tasks_limit,
41+
)
42+
if not r.ok():
43+
return
44+
PREVIOUS_TASKS = r.data
45+
46+
await TSOP.sop_agent_curd(
3547
project_id,
3648
space_id,
3749
task,
50+
PREVIOUS_TASKS,
3851
messages_data,
3952
max_iterations=project_config.default_sop_agent_max_iterations,
4053
project_config=project_config,

0 commit comments

Comments
 (0)