Skip to content
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
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.250.213"
VERSION = "0.250.214"
IS_DEVELOPMENT = is_development_env_enabled()

SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax')
Expand Down
212 changes: 210 additions & 2 deletions application/single_app/route_backend_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@

AGENT_INSTRUCTION_FIELD_LIMIT = 6000
AGENT_INSTRUCTION_OUTPUT_TOKEN_LIMIT = 1400
AGENT_INSTRUCTION_CONTEXT_ITEM_LIMIT = 40

Check warning on line 67 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
AGENT_INSTRUCTION_CONTEXT_CAPABILITY_LIMIT = 30

Check warning on line 68 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
AGENT_INSTRUCTION_CONTEXT_LABEL_LIMIT = 200

Check warning on line 69 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
AGENT_INSTRUCTION_CONTEXT_DESCRIPTION_LIMIT = 400

Check warning on line 70 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
# Per-item caps alone still allow a very large prompt, so the rendered context

Check warning on line 71 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
# blocks also share a single total character budget.
AGENT_INSTRUCTION_CONTEXT_TOTAL_LIMIT = 8000

Check warning on line 73 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
AGENT_INSTRUCTION_CONTEXT_TRUNCATION_NOTE = '- (additional items omitted)'

Check warning on line 74 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.


def _redact_catalog_agent_instructions(catalog):
Expand Down Expand Up @@ -142,18 +150,202 @@
)


def _build_agent_instruction_messages(display_name, description, brief, existing_instructions):
def _truncate_agent_instruction_context_block(block, budget):

Check warning on line 153 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
"""Trim a rendered context block to fit the shared character budget.

Per-item caps bound each entry, but not how many entries arrive, so the
combined blocks also share a total budget before they reach the model.
"""
if not block:
return ''
if len(block) <= budget:
return block

lines = block.split('\n')
header = lines[0]
note = AGENT_INSTRUCTION_CONTEXT_TRUNCATION_NOTE

Check warning on line 166 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
if len(header) + len(note) + 1 > budget:
return ''

kept = [header]
used = len(header)
for line in lines[1:]:
projected = used + 1 + len(line)
if projected + len(note) + 1 > budget:
break
kept.append(line)
used = projected

kept.append(note)
return '\n'.join(kept)


def _apply_agent_instruction_context_budget(actions_context, knowledge_context):

Check warning on line 183 in application/single_app/route_backend_agents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
"""Bound the combined size of the rendered action and knowledge blocks."""
total_budget = AGENT_INSTRUCTION_CONTEXT_TOTAL_LIMIT
if len(actions_context) + len(knowledge_context) <= total_budget:
return actions_context, knowledge_context

# Each block is guaranteed half the budget, and any headroom the other block
# does not need rolls over.
half_budget = total_budget // 2
actions_budget = half_budget + max(0, half_budget - len(knowledge_context))
trimmed_actions = _truncate_agent_instruction_context_block(actions_context, actions_budget)
knowledge_budget = total_budget - len(trimmed_actions)
trimmed_knowledge = _truncate_agent_instruction_context_block(knowledge_context, knowledge_budget)
return trimmed_actions, trimmed_knowledge


def _format_agent_instruction_token_value(value):
"""Render a reference token value, quoting it when it contains separators."""
normalized_value = _normalize_agent_instruction_draft_input(
value,
AGENT_INSTRUCTION_CONTEXT_LABEL_LIMIT,
)
if not normalized_value:
return ''
if any(character in normalized_value for character in (' ', ':', '"')):
return '"{0}"'.format(normalized_value.replace('"', "'"))
return normalized_value


def _format_agent_instruction_actions_context(selected_actions):
"""Summarize the client-supplied selected actions for the drafting prompt.

The payload is untrusted display context only. It is normalized, truncated,
and bounded here so it can never be used to widen authorization or to bloat
the prompt.
"""
if not isinstance(selected_actions, list):
return ''

lines = []
for action in selected_actions[:AGENT_INSTRUCTION_CONTEXT_ITEM_LIMIT]:
if not isinstance(action, dict):
continue
label = _normalize_agent_instruction_draft_input(
action.get('display_name') or action.get('name'),
AGENT_INSTRUCTION_CONTEXT_LABEL_LIMIT,
)
if not label:
continue

token_value = _format_agent_instruction_token_value(label)
description = _normalize_agent_instruction_draft_input(
action.get('description'),
AGENT_INSTRUCTION_CONTEXT_DESCRIPTION_LIMIT,
)
action_type = _normalize_agent_instruction_draft_input(action.get('type'), 100)

detail = f'- #action:{token_value}'
if action_type:
detail += f' (type: {action_type})'
if description:
detail += f' — {description}'
lines.append(detail)

capabilities = action.get('capabilities')
if not isinstance(capabilities, list):
continue
for capability in capabilities[:AGENT_INSTRUCTION_CONTEXT_CAPABILITY_LIMIT]:
if not isinstance(capability, dict):
continue
capability_key = _normalize_agent_instruction_draft_input(
capability.get('key'),
AGENT_INSTRUCTION_CONTEXT_LABEL_LIMIT,
)
if not capability_key:
continue
capability_label = _normalize_agent_instruction_draft_input(
capability.get('label'),
AGENT_INSTRUCTION_CONTEXT_LABEL_LIMIT,
)
capability_token = _format_agent_instruction_token_value(capability_key)
capability_line = f' - #action:{token_value}:{capability_token}'
if capability_label:
capability_line += f' — {capability_label}'
lines.append(capability_line)

if not lines:
return ''
return 'Actions selected for this agent (reference only these):\n' + '\n'.join(lines)


def _format_agent_instruction_knowledge_context(assigned_knowledge):
"""Summarize the client-supplied assigned knowledge for the drafting prompt."""
if not isinstance(assigned_knowledge, dict) or not assigned_knowledge.get('enabled'):
return ''

lines = []

def _append_entries(entries, token_type, label_keys, detail_keys=()):
if not isinstance(entries, list):
return
for entry in entries[:AGENT_INSTRUCTION_CONTEXT_ITEM_LIMIT]:
if isinstance(entry, dict):
label = next(
(entry.get(key) for key in label_keys if str(entry.get(key) or '').strip()),
'',
)
detail = next(
(entry.get(key) for key in detail_keys if str(entry.get(key) or '').strip()),
'',
)
else:
label = entry
detail = ''

token_value = _format_agent_instruction_token_value(label)
if not token_value:
continue

line = f'- #knowledge:{token_type}:{token_value}'
normalized_detail = _normalize_agent_instruction_draft_input(
detail,
AGENT_INSTRUCTION_CONTEXT_DESCRIPTION_LIMIT,
)
if normalized_detail:
line += f' — {normalized_detail}'
lines.append(line)

_append_entries(assigned_knowledge.get('sources'), 'workspace', ('name', 'id'), ('scope',))
_append_entries(assigned_knowledge.get('documents'), 'doc', ('title', 'file_name'), ('source_name',))
_append_entries(assigned_knowledge.get('tags'), 'tag', ('name', 'tag'))
_append_entries(assigned_knowledge.get('web_sources'), 'web', ('url',), ('mode_label', 'mode'))

if not lines:
return ''
return 'Assigned knowledge available to this agent (reference only these):\n' + '\n'.join(lines)


def _build_agent_instruction_messages(
display_name,
description,
brief,
existing_instructions,
*,
selected_actions=None,
assigned_knowledge=None,
):
"""Build the prompt for drafting editable SimpleChat agent instructions."""
display_name = _normalize_agent_instruction_draft_input(display_name, 500)
description = _normalize_agent_instruction_draft_input(description)
brief = _normalize_agent_instruction_draft_input(brief)
existing_instructions = _normalize_agent_instruction_draft_input(existing_instructions)
actions_context = _format_agent_instruction_actions_context(selected_actions)
knowledge_context = _format_agent_instruction_knowledge_context(assigned_knowledge)
actions_context, knowledge_context = _apply_agent_instruction_context_budget(
actions_context,
knowledge_context,
)

user_sections = [
f'Agent display name: {display_name or "Not provided"}',
f'Agent description: {description or "Not provided"}',
f'Author brief: {brief or "Not provided"}',
]
user_sections.append(actions_context or 'Actions selected for this agent: None')
user_sections.append(knowledge_context or 'Assigned knowledge available to this agent: None')
if existing_instructions:
user_sections.append(f'Existing instructions to improve or preserve where useful:\n{existing_instructions}')

Expand All @@ -164,7 +356,21 @@
'You write production-ready SimpleChat agent instructions. '
'Return only the finished instructions in Markdown. '
'Be specific about role, goals, workflow, boundaries, tool use, and response style. '
'Do not include code fences, preambles, or commentary about how the instructions were created.'
'Do not include code fences, preambles, or commentary about how the instructions were created.\n\n'
'SimpleChat instructions support inline reference tokens that point at the actions and '
'knowledge already configured for this agent. Use them wherever the instructions explain '
'when or why to use a capability or a document:\n'
' #action:<ActionName> references a selected action.\n'
' #action:<ActionName>:<capability_key> references one enabled capability of that action.\n'
' #knowledge:doc:<Document Title> references an assigned document.\n'
' #knowledge:workspace:<Workspace Name> references an assigned workspace.\n'
' #knowledge:tag:<tag> references an assigned tag limit.\n'
' #knowledge:web:<url> references an assigned web source.\n'
'Wrap a value in double quotes when it contains a space or a colon, for example '
'#knowledge:doc:"Employee Handbook.pdf".\n'
'Only reference actions, capabilities, and knowledge items that appear in the provided lists. '
'Never invent a token for something that was not listed, and omit the tokens entirely when '
'no actions or knowledge were provided.'
),
},
{
Expand Down Expand Up @@ -713,6 +919,8 @@
description,
brief,
existing_instructions,
selected_actions=request_data.get('selected_actions'),
assigned_knowledge=request_data.get('assigned_knowledge'),
)
response = client.chat.completions.create(
**_build_agent_instruction_api_params(model_name, messages)
Expand Down
Loading
Loading