Skip to content

Commit efaef34

Browse files
authored
refactor(core, api, ui, sdk-ts, sdk-py, docs): remove support for the system role in the messages (#70)
* refactor(core): remove the 'system' role option * refactor(api): remove support for 'system' role in messages and update related tests * refactor(ui): remove 'system' role from messages and update related components * refactor(sdk-ts): further remove 'system' role from AcontextMessage and related functions * refactor(sdk-py): eliminate 'system' role * refactor(docs): remove 'system' role from message examples and update best practices
1 parent a3d70a0 commit efaef34

19 files changed

Lines changed: 37 additions & 173 deletions

File tree

docs/integrations/agno.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ Agno uses OpenAI-compatible message format, which works seamlessly with Acontext
275275
```python
276276
# Agno message format (compatible with Acontext)
277277
message = {
278-
"role": "user", # or "assistant", "system"
278+
"role": "user", # or "assistant"
279279
"content": "Your message here"
280280
}
281281

docs/integrations/openai-python.mdx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,7 @@ Handle tool calls in a loop until the agent provides a final response:
182182
```python
183183
def run_agent(client: OpenAI, conversation: list[dict]) -> tuple[str, list[dict]]:
184184
"""Run the agent with tool calling support."""
185-
messages_to_send = [
186-
{"role": "system", "content": "You are a helpful assistant"}
187-
] + conversation
185+
messages_to_send = list(conversation)
188186

189187
new_messages = []
190188
max_iterations = 10
@@ -420,7 +418,7 @@ acontext_client.sessions.send_message(session_id=session_id, blob=tool_result)
420418
## Best Practices
421419

422420
<Tip>
423-
**Message format**: OpenAI message format is compatible with Acontext, so you can send messages directly without conversion. This includes user, assistant, system, and tool messages.
421+
**Message format**: OpenAI message format is compatible with Acontext, so you can send messages directly without conversion. This includes user, assistant, and tool messages. System prompts should be handled through session-level or skill-level configuration rather than as messages.
424422
</Tip>
425423

426424
<Tip>

docs/integrations/openai-typescript.mdx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ async function runAgent(
198198
conversation: any[]
199199
): Promise<[string, any[]]> {
200200
const messagesToSend: any[] = [
201-
{ role: 'system', content: 'You are a helpful assistant' },
202201
...conversation,
203202
];
204203

src/client/acontext-py/src/acontext/messages.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ class AcontextMessage:
3131
Represents an Acontext-format message payload.
3232
"""
3333

34-
role: Literal["user", "assistant", "system"]
34+
role: Literal["user", "assistant"]
3535
parts: list[MessagePart]
3636
meta: Mapping[str, Any] | None = None
3737

3838

3939
def build_acontext_message(
4040
*,
41-
role: Literal["user", "assistant", "system"],
41+
role: Literal["user", "assistant"],
4242
parts: Sequence[MessagePart | str | Mapping[str, Any]],
4343
meta: Mapping[str, Any] | None = None,
4444
) -> AcontextMessage:
4545
"""
4646
Construct an Acontext-format message blob and associated multipart files.
4747
"""
48-
if role not in {"user", "assistant", "system"}:
49-
raise ValueError("role must be one of {'user', 'assistant', 'system'}")
48+
if role not in {"user", "assistant"}:
49+
raise ValueError("role must be one of {'user', 'assistant'}")
5050

5151
normalized_parts = [normalize_message_part(part) for part in parts]
5252

src/client/acontext-py/src/acontext/types/session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class Message(BaseModel):
6565
id: str = Field(..., description="Message UUID")
6666
session_id: str = Field(..., description="Session UUID")
6767
parent_id: str | None = Field(None, description="Parent message UUID")
68-
role: str = Field(..., description="Message role: 'user', 'assistant', or 'system'")
68+
role: str = Field(..., description="Message role: 'user' or 'assistant'")
6969
meta: dict[str, Any] = Field(..., description="Message metadata")
7070
parts: list[Part] = Field(..., description="List of message parts")
7171
task_id: str | None = Field(None, description="Task UUID if associated with a task")

src/client/acontext-ts/src/messages.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ export class MessagePart {
5959
}
6060

6161
export const AcontextMessageSchema = z.object({
62-
role: z.enum(['user', 'assistant', 'system']),
62+
role: z.enum(['user', 'assistant']),
6363
parts: z.array(MessagePartSchema),
6464
meta: z.record(z.string(), z.unknown()).nullable().optional(),
6565
});
6666

6767
export type AcontextMessageInput = z.infer<typeof AcontextMessageSchema>;
6868

6969
export class AcontextMessage {
70-
role: 'user' | 'assistant' | 'system';
70+
role: 'user' | 'assistant';
7171
parts: MessagePart[];
7272
meta?: Record<string, unknown> | null;
7373

@@ -89,12 +89,12 @@ export class AcontextMessage {
8989
}
9090

9191
export function buildAcontextMessage(options: {
92-
role: 'user' | 'assistant' | 'system';
92+
role: 'user' | 'assistant';
9393
parts: (MessagePart | string | MessagePartInput)[];
9494
meta?: Record<string, unknown> | null;
9595
}): AcontextMessage {
96-
if (!['user', 'assistant', 'system'].includes(options.role)) {
97-
throw new Error("role must be one of {'user', 'assistant', 'system'}");
96+
if (!['user', 'assistant'].includes(options.role)) {
97+
throw new Error("role must be one of {'user', 'assistant'}");
9898
}
9999

100100
const normalizedParts = options.parts.map((part) => {

src/server/api/go/internal/modules/handler/session_test.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -764,28 +764,6 @@ func TestSessionHandler_SendMessage(t *testing.T) {
764764
},
765765
expectedStatus: http.StatusCreated,
766766
},
767-
{
768-
name: "openai format - system message",
769-
sessionIDParam: sessionID.String(),
770-
requestBody: map[string]interface{}{
771-
"format": "openai",
772-
"blob": map[string]interface{}{
773-
"role": "system",
774-
"content": "You are a helpful assistant that speaks like a pirate.",
775-
},
776-
},
777-
setup: func(svc *MockSessionService) {
778-
expectedMessage := &model.Message{
779-
ID: uuid.New(),
780-
SessionID: sessionID,
781-
Role: "system",
782-
}
783-
svc.On("SendMessage", mock.Anything, mock.MatchedBy(func(in service.SendMessageInput) bool {
784-
return in.ProjectID == projectID && in.SessionID == sessionID && in.Role == "system"
785-
})).Return(expectedMessage, nil)
786-
},
787-
expectedStatus: http.StatusCreated,
788-
},
789767
{
790768
name: "openai format - assistant with multiple tool_calls",
791769
sessionIDParam: sessionID.String(),

src/server/api/go/internal/modules/model/message.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type Message struct {
2323
Parent *Message `gorm:"foreignKey:ParentID;references:ID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;" json:"-"`
2424
Children []Message `gorm:"foreignKey:ParentID;constraint:OnDelete:CASCADE,OnUpdate:CASCADE;" json:"-"`
2525

26-
Role string `gorm:"type:text;not null;check:role IN ('user','assistant','system')" json:"role"`
26+
Role string `gorm:"type:text;not null;check:role IN ('user','assistant')" json:"role"`
2727

2828
Meta datatypes.JSONType[map[string]any] `gorm:"type:jsonb;not null;default:'{}'" swaggertype:"object" json:"meta"`
2929

src/server/api/go/internal/pkg/converter/anthropic.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ func (c *AnthropicConverter) Convert(messages []model.Message, publicURLs map[st
2121
result := make([]anthropic.MessageParam, 0, len(messages))
2222

2323
for _, msg := range messages {
24-
// Skip system messages - they should be handled separately via system parameter
25-
if msg.Role == "system" {
26-
continue
27-
}
28-
2924
anthropicMsg := c.convertMessage(msg, publicURLs)
3025
result = append(result, anthropicMsg)
3126
}
@@ -48,7 +43,6 @@ func (c *AnthropicConverter) convertMessage(msg model.Message, publicURLs map[st
4843

4944
func (c *AnthropicConverter) convertRole(role string) string {
5045
// Anthropic roles: "user", "assistant"
51-
// Note: "system" messages should be passed via the top-level system parameter
5246
switch role {
5347
case "assistant":
5448
return "assistant"

src/server/api/go/internal/pkg/converter/openai.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ func (c *OpenAIConverter) Convert(messages []model.Message, publicURLs map[strin
3131
case "assistant":
3232
assistantMsg := c.convertToAssistantMessage(msg)
3333
result = append(result, assistantMsg)
34-
case "system":
35-
systemMsg := c.convertToSystemMessage(msg)
36-
result = append(result, systemMsg)
3734
default:
3835
// Default to user message
3936
userMsg := c.convertToUserMessage(msg, publicURLs)
@@ -196,33 +193,6 @@ func (c *OpenAIConverter) convertToAssistantMessage(msg model.Message) openai.Ch
196193
}
197194
}
198195

199-
func (c *OpenAIConverter) convertToSystemMessage(msg model.Message) openai.ChatCompletionMessageParamUnion {
200-
// Extract text from parts
201-
text := ""
202-
for _, part := range msg.Parts {
203-
if part.Type == "text" {
204-
text += part.Text
205-
}
206-
}
207-
208-
systemParam := openai.ChatCompletionSystemMessageParam{
209-
Content: openai.ChatCompletionSystemMessageParamContentUnion{
210-
OfString: param.NewOpt(text),
211-
},
212-
}
213-
214-
// Add name field from message meta if present
215-
if metaData := msg.Meta.Data(); len(metaData) > 0 {
216-
if name, ok := metaData["name"].(string); ok && name != "" {
217-
systemParam.Name = param.NewOpt(name)
218-
}
219-
}
220-
221-
return openai.ChatCompletionMessageParamUnion{
222-
OfSystem: &systemParam,
223-
}
224-
}
225-
226196
func (c *OpenAIConverter) convertToToolMessage(msg model.Message) openai.ChatCompletionMessageParamUnion {
227197
// Extract tool result information
228198
toolCallID := c.extractToolCallID(msg.Parts)

0 commit comments

Comments
 (0)