unique_orchestrator 1.11.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of unique_orchestrator might be problematic. Click here for more details.
- unique_orchestrator/config.py +401 -0
- unique_orchestrator/prompts/generic_reference_prompt.jinja2 +46 -0
- unique_orchestrator/prompts/system_prompt.jinja2 +166 -0
- unique_orchestrator/prompts/user_message_prompt.jinja2 +23 -0
- unique_orchestrator/tests/test_unique_ai_get_filtered_user_metadata.py +259 -0
- unique_orchestrator/tests/test_unique_ai_log_tool_calls.py +729 -0
- unique_orchestrator/tests/test_unique_ai_reference_order.py +134 -0
- unique_orchestrator/tests/test_unique_ai_update_debug_info_for_tool_control.py +339 -0
- unique_orchestrator/unique_ai.py +537 -0
- unique_orchestrator/unique_ai_builder.py +568 -0
- unique_orchestrator-1.11.1.dist-info/LICENSE +1 -0
- unique_orchestrator-1.11.1.dist-info/METADATA +199 -0
- unique_orchestrator-1.11.1.dist-info/RECORD +14 -0
- unique_orchestrator-1.11.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated, Any, Generic, Literal, TypeVar
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator
|
|
6
|
+
from unique_deep_research.config import DeepResearchToolConfig
|
|
7
|
+
from unique_deep_research.service import DeepResearchTool
|
|
8
|
+
from unique_follow_up_questions.config import FollowUpQuestionsConfig
|
|
9
|
+
from unique_internal_search.config import InternalSearchConfig
|
|
10
|
+
from unique_internal_search.service import InternalSearchTool
|
|
11
|
+
from unique_stock_ticker.config import StockTickerConfig
|
|
12
|
+
from unique_swot import SwotAnalysisTool, SwotAnalysisToolConfig
|
|
13
|
+
from unique_toolkit._common.validators import (
|
|
14
|
+
LMI,
|
|
15
|
+
ClipInt,
|
|
16
|
+
get_LMI_default_field,
|
|
17
|
+
)
|
|
18
|
+
from unique_toolkit.agentic.evaluation.hallucination.constants import (
|
|
19
|
+
HallucinationConfig,
|
|
20
|
+
)
|
|
21
|
+
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
22
|
+
from unique_toolkit.agentic.history_manager.history_manager import (
|
|
23
|
+
UploadedContentConfig,
|
|
24
|
+
)
|
|
25
|
+
from unique_toolkit.agentic.loop_runner import (
|
|
26
|
+
QWEN_FORCED_TOOL_CALL_INSTRUCTION,
|
|
27
|
+
QWEN_LAST_ITERATION_INSTRUCTION,
|
|
28
|
+
PlanningConfig,
|
|
29
|
+
)
|
|
30
|
+
from unique_toolkit.agentic.responses_api import (
|
|
31
|
+
DisplayCodeInterpreterFilesPostProcessorConfig,
|
|
32
|
+
ShowExecutedCodePostprocessorConfig,
|
|
33
|
+
)
|
|
34
|
+
from unique_toolkit.agentic.tools.a2a import (
|
|
35
|
+
REFERENCING_INSTRUCTIONS_FOR_SYSTEM_PROMPT,
|
|
36
|
+
REFERENCING_INSTRUCTIONS_FOR_USER_PROMPT,
|
|
37
|
+
)
|
|
38
|
+
from unique_toolkit.agentic.tools.a2a.evaluation import SubAgentEvaluationServiceConfig
|
|
39
|
+
from unique_toolkit.agentic.tools.config import get_configuration_dict
|
|
40
|
+
from unique_toolkit.agentic.tools.openai_builtin.manager import (
|
|
41
|
+
OpenAICodeInterpreterConfig,
|
|
42
|
+
)
|
|
43
|
+
from unique_toolkit.agentic.tools.tool import ToolBuildConfig
|
|
44
|
+
from unique_toolkit.agentic.tools.tool_progress_reporter import (
|
|
45
|
+
ToolProgressReporterConfig,
|
|
46
|
+
)
|
|
47
|
+
from unique_toolkit.language_model.default_language_model import DEFAULT_GPT_4o
|
|
48
|
+
from unique_web_search.config import WebSearchConfig
|
|
49
|
+
from unique_web_search.service import WebSearchTool
|
|
50
|
+
|
|
51
|
+
DeactivatedNone = Annotated[
|
|
52
|
+
None,
|
|
53
|
+
Field(title="Deactivated", description="None"),
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class SpaceType(StrEnum):
|
|
58
|
+
UNIQUE_CUSTOM = "unique_custom"
|
|
59
|
+
UNIQUE_AI = "unique_ai"
|
|
60
|
+
UNIQUE_TRANSLATION = "unique_translation"
|
|
61
|
+
UNIQUE_MAGIC_TABLE = ""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
T = TypeVar("T", bound=SpaceType)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class SpaceConfigBase(BaseModel, Generic[T]):
|
|
68
|
+
"""Base class for space configuration."""
|
|
69
|
+
|
|
70
|
+
model_config = get_configuration_dict(frozen=True)
|
|
71
|
+
type: T = Field(description="The type of the space.")
|
|
72
|
+
|
|
73
|
+
project_name: str = Field(
|
|
74
|
+
default="Unique AI",
|
|
75
|
+
description="The project name as optained from spaces 2.0",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
language_model: LMI = get_LMI_default_field(DEFAULT_GPT_4o)
|
|
79
|
+
|
|
80
|
+
custom_instructions: str = Field(
|
|
81
|
+
default="",
|
|
82
|
+
description="A custom instruction provided by the system admin.",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
tools: list[ToolBuildConfig] = Field(
|
|
86
|
+
default=[
|
|
87
|
+
ToolBuildConfig(
|
|
88
|
+
name=InternalSearchTool.name,
|
|
89
|
+
configuration=InternalSearchConfig(
|
|
90
|
+
exclude_uploaded_files=True,
|
|
91
|
+
),
|
|
92
|
+
),
|
|
93
|
+
ToolBuildConfig(
|
|
94
|
+
name=WebSearchTool.name,
|
|
95
|
+
configuration=WebSearchConfig(),
|
|
96
|
+
),
|
|
97
|
+
ToolBuildConfig(
|
|
98
|
+
name=DeepResearchTool.name,
|
|
99
|
+
configuration=DeepResearchToolConfig(),
|
|
100
|
+
),
|
|
101
|
+
ToolBuildConfig(
|
|
102
|
+
name=SwotAnalysisTool.name,
|
|
103
|
+
configuration=SwotAnalysisToolConfig(),
|
|
104
|
+
),
|
|
105
|
+
],
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
@field_validator("tools", mode="after")
|
|
109
|
+
@classmethod
|
|
110
|
+
def set_input_context_size(
|
|
111
|
+
cls, tools: list[ToolBuildConfig], info: ValidationInfo
|
|
112
|
+
) -> list[ToolBuildConfig]:
|
|
113
|
+
for tool in tools:
|
|
114
|
+
if tool.name == InternalSearchTool.name:
|
|
115
|
+
tool.configuration.language_model_max_input_tokens = ( # type: ignore
|
|
116
|
+
info.data["language_model"].token_limits.token_limit_input
|
|
117
|
+
)
|
|
118
|
+
elif tool.name == WebSearchTool.name:
|
|
119
|
+
tool.configuration.language_model_max_input_tokens = ( # type: ignore
|
|
120
|
+
info.data["language_model"].token_limits.token_limit_input
|
|
121
|
+
)
|
|
122
|
+
return tools
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class UniqueAISpaceConfig(SpaceConfigBase):
|
|
126
|
+
"""Contains configuration for the entities that a space provides."""
|
|
127
|
+
|
|
128
|
+
type: Literal[SpaceType.UNIQUE_AI] = SpaceType.UNIQUE_AI
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
UniqueAISpaceConfig.model_rebuild()
|
|
132
|
+
|
|
133
|
+
LIMIT_MAX_TOOL_CALLS_PER_ITERATION = 50
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class QwenConfig(BaseModel):
|
|
137
|
+
"""Qwen specific configuration."""
|
|
138
|
+
|
|
139
|
+
model_config = get_configuration_dict()
|
|
140
|
+
|
|
141
|
+
forced_tool_call_instruction: str = Field(
|
|
142
|
+
default=QWEN_FORCED_TOOL_CALL_INSTRUCTION,
|
|
143
|
+
description="This instruction is appended to the user message for every forced tool call.",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
last_iteration_instruction: str = Field(
|
|
147
|
+
default=QWEN_LAST_ITERATION_INSTRUCTION,
|
|
148
|
+
description="An assistant message with this instruction is generated once the maximum number of loop iterations is reached.",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class ModelSpecificConfig(BaseModel):
|
|
153
|
+
"""Model-specific loop configurations."""
|
|
154
|
+
|
|
155
|
+
model_config = get_configuration_dict()
|
|
156
|
+
|
|
157
|
+
qwen: QwenConfig = QwenConfig()
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class LoopConfiguration(BaseModel):
|
|
161
|
+
model_config = get_configuration_dict()
|
|
162
|
+
|
|
163
|
+
max_tool_calls_per_iteration: Annotated[
|
|
164
|
+
int,
|
|
165
|
+
*ClipInt(min_value=1, max_value=LIMIT_MAX_TOOL_CALLS_PER_ITERATION),
|
|
166
|
+
] = 10
|
|
167
|
+
|
|
168
|
+
planning_config: (
|
|
169
|
+
Annotated[PlanningConfig, Field(title="Active")] | DeactivatedNone
|
|
170
|
+
) = Field(default=None, description="Planning configuration.")
|
|
171
|
+
|
|
172
|
+
model_specific: ModelSpecificConfig = ModelSpecificConfig()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class EvaluationConfig(BaseModel):
|
|
176
|
+
model_config = get_configuration_dict()
|
|
177
|
+
max_review_steps: int = 3
|
|
178
|
+
hallucination_config: HallucinationConfig = HallucinationConfig()
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# ------------------------------------------------------------
|
|
182
|
+
# Space 2.0 Config
|
|
183
|
+
# ------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class UniqueAIPromptConfig(BaseModel):
|
|
187
|
+
model_config = get_configuration_dict(frozen=True)
|
|
188
|
+
|
|
189
|
+
system_prompt_template: str = Field(
|
|
190
|
+
default_factory=lambda: (
|
|
191
|
+
Path(__file__).parent / "prompts" / "system_prompt.jinja2"
|
|
192
|
+
).read_text(),
|
|
193
|
+
description="The system prompt template as a Jinja2 template string.",
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
user_message_prompt_template: str = Field(
|
|
197
|
+
default_factory=lambda: (
|
|
198
|
+
Path(__file__).parent / "prompts" / "user_message_prompt.jinja2"
|
|
199
|
+
).read_text(),
|
|
200
|
+
description="The user message prompt template as a Jinja2 template string.",
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
user_metadata: list[str] = Field(
|
|
204
|
+
default=[],
|
|
205
|
+
title="User Metadata",
|
|
206
|
+
description="User metadata fields to be ingested in the system prompt.",
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class UniqueAIServices(BaseModel):
|
|
211
|
+
"""Determine the services the agent is using
|
|
212
|
+
|
|
213
|
+
All services are optional and can be disabled by setting them to None.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
model_config = get_configuration_dict(frozen=True)
|
|
217
|
+
|
|
218
|
+
follow_up_questions_config: (
|
|
219
|
+
Annotated[
|
|
220
|
+
FollowUpQuestionsConfig,
|
|
221
|
+
Field(
|
|
222
|
+
title="Active",
|
|
223
|
+
),
|
|
224
|
+
]
|
|
225
|
+
| DeactivatedNone
|
|
226
|
+
) = FollowUpQuestionsConfig()
|
|
227
|
+
|
|
228
|
+
stock_ticker_config: (
|
|
229
|
+
Annotated[StockTickerConfig, Field(title="Active")] | DeactivatedNone
|
|
230
|
+
) = StockTickerConfig()
|
|
231
|
+
|
|
232
|
+
evaluation_config: (
|
|
233
|
+
Annotated[
|
|
234
|
+
EvaluationConfig,
|
|
235
|
+
Field(title="Active"),
|
|
236
|
+
]
|
|
237
|
+
| DeactivatedNone
|
|
238
|
+
) = EvaluationConfig(
|
|
239
|
+
hallucination_config=HallucinationConfig(),
|
|
240
|
+
max_review_steps=0,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
uploaded_content_config: UploadedContentConfig = UploadedContentConfig()
|
|
244
|
+
|
|
245
|
+
tool_progress_reporter_config: ToolProgressReporterConfig = (
|
|
246
|
+
ToolProgressReporterConfig()
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class InputTokenDistributionConfig(BaseModel):
|
|
251
|
+
model_config = get_configuration_dict(frozen=True)
|
|
252
|
+
|
|
253
|
+
percent_for_history: float = Field(
|
|
254
|
+
default=0.2,
|
|
255
|
+
ge=0.0,
|
|
256
|
+
lt=1.0,
|
|
257
|
+
description="The fraction of the max input tokens that will be reserved for the history.",
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
def max_history_tokens(self, max_input_token: int) -> int:
|
|
261
|
+
return int(self.percent_for_history * max_input_token)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class SubAgentsReferencingConfig(BaseModel):
|
|
265
|
+
model_config = get_configuration_dict()
|
|
266
|
+
|
|
267
|
+
referencing_instructions_for_system_prompt: str = Field(
|
|
268
|
+
default=REFERENCING_INSTRUCTIONS_FOR_SYSTEM_PROMPT,
|
|
269
|
+
description="Referencing instructions for the main agent's system prompt.",
|
|
270
|
+
)
|
|
271
|
+
referencing_instructions_for_user_prompt: str = Field(
|
|
272
|
+
default=REFERENCING_INSTRUCTIONS_FOR_USER_PROMPT,
|
|
273
|
+
description="Referencing instructions for the main agent's user prompt. Should correspond to a short reminder.",
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class SubAgentsConfig(BaseModel):
|
|
278
|
+
model_config = get_configuration_dict()
|
|
279
|
+
|
|
280
|
+
referencing_config: (
|
|
281
|
+
Annotated[SubAgentsReferencingConfig, Field(title="Active")] | DeactivatedNone
|
|
282
|
+
) = SubAgentsReferencingConfig()
|
|
283
|
+
evaluation_config: (
|
|
284
|
+
Annotated[SubAgentEvaluationServiceConfig, Field(title="Active")]
|
|
285
|
+
| DeactivatedNone
|
|
286
|
+
) = SubAgentEvaluationServiceConfig()
|
|
287
|
+
|
|
288
|
+
sleep_time_before_update: float = Field(
|
|
289
|
+
default=0.5,
|
|
290
|
+
description="Time to sleep before updating the main agent message to display the sub agent responses. Temporary fix to avoid rendering issues.",
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class CodeInterpreterExtendedConfig(BaseModel):
|
|
295
|
+
model_config = get_configuration_dict()
|
|
296
|
+
|
|
297
|
+
generated_files_config: DisplayCodeInterpreterFilesPostProcessorConfig = Field(
|
|
298
|
+
default=DisplayCodeInterpreterFilesPostProcessorConfig(),
|
|
299
|
+
title="Generated files config",
|
|
300
|
+
description="Display config for generated files",
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
executed_code_display_config: (
|
|
304
|
+
Annotated[
|
|
305
|
+
ShowExecutedCodePostprocessorConfig,
|
|
306
|
+
Field(title="Active"),
|
|
307
|
+
]
|
|
308
|
+
| DeactivatedNone
|
|
309
|
+
) = Field(
|
|
310
|
+
ShowExecutedCodePostprocessorConfig(),
|
|
311
|
+
description="If active, generated code will be prepended to the LLM answer",
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
tool_config: OpenAICodeInterpreterConfig = Field(
|
|
315
|
+
default=OpenAICodeInterpreterConfig(),
|
|
316
|
+
title="Tool config",
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
class ResponsesApiConfig(BaseModel):
|
|
321
|
+
model_config = get_configuration_dict(frozen=True)
|
|
322
|
+
|
|
323
|
+
code_interpreter: (
|
|
324
|
+
Annotated[CodeInterpreterExtendedConfig, Field(title="Active")]
|
|
325
|
+
| DeactivatedNone
|
|
326
|
+
) = Field(
|
|
327
|
+
default=None,
|
|
328
|
+
description="If active, the main agent will have acces to the OpenAI Code Interpreter tool",
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
use_responses_api: bool = Field(
|
|
332
|
+
default=False,
|
|
333
|
+
description="If set, the main agent will use the Responses API from OpenAI",
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class ExperimentalConfig(BaseModel):
|
|
338
|
+
"""Experimental features this part of the configuration might evolve in the future continuously"""
|
|
339
|
+
|
|
340
|
+
model_config = get_configuration_dict(frozen=True)
|
|
341
|
+
|
|
342
|
+
thinking_steps_display: bool = False
|
|
343
|
+
|
|
344
|
+
# TODO: @gustavhartz, the Hallucination check should be triggered if enabled and the answer contains references.
|
|
345
|
+
force_checks_on_stream_response_references: list[EvaluationMetricName] = Field(
|
|
346
|
+
default=[EvaluationMetricName.HALLUCINATION],
|
|
347
|
+
description="A list of checks to force on references. This is used to add hallucination check to references without new tool calls.",
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# TODO: The temperature should be used via the additional_llm_options
|
|
351
|
+
# then the additional_llm_options migth should eventually be closer to the LangaugeModelInfo
|
|
352
|
+
temperature: float = Field(
|
|
353
|
+
default=0.0,
|
|
354
|
+
ge=0.0,
|
|
355
|
+
le=10.0,
|
|
356
|
+
description="The temperature to use for the LLM.",
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
additional_llm_options: dict[str, Any] = Field(
|
|
360
|
+
default={},
|
|
361
|
+
description="Additional options to pass to the LLM.",
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
loop_configuration: LoopConfiguration = LoopConfiguration(
|
|
365
|
+
max_tool_calls_per_iteration=10
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
sub_agents_config: SubAgentsConfig = SubAgentsConfig()
|
|
369
|
+
|
|
370
|
+
responses_api_config: ResponsesApiConfig = ResponsesApiConfig()
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class UniqueAIAgentConfig(BaseModel):
|
|
374
|
+
model_config = get_configuration_dict(frozen=True)
|
|
375
|
+
|
|
376
|
+
max_loop_iterations: int = 8
|
|
377
|
+
|
|
378
|
+
input_token_distribution: InputTokenDistributionConfig = Field(
|
|
379
|
+
default=InputTokenDistributionConfig(),
|
|
380
|
+
description="The distribution of the input tokens.",
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
prompt_config: UniqueAIPromptConfig = UniqueAIPromptConfig()
|
|
384
|
+
|
|
385
|
+
services: UniqueAIServices = UniqueAIServices()
|
|
386
|
+
|
|
387
|
+
experimental: ExperimentalConfig = ExperimentalConfig()
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class UniqueAIConfig(BaseModel):
|
|
391
|
+
model_config = get_configuration_dict(frozen=True)
|
|
392
|
+
|
|
393
|
+
space: UniqueAISpaceConfig = UniqueAISpaceConfig()
|
|
394
|
+
|
|
395
|
+
agent: UniqueAIAgentConfig = UniqueAIAgentConfig()
|
|
396
|
+
|
|
397
|
+
@model_validator(mode="after")
|
|
398
|
+
def disable_sub_agent_referencing_if_not_used(self) -> "UniqueAIConfig":
|
|
399
|
+
if not any(tool.is_sub_agent for tool in self.space.tools):
|
|
400
|
+
self.agent.experimental.sub_agents_config.referencing_config = None
|
|
401
|
+
return self
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Generic Reference Guidelines - ONLY FOLLOW IF NOTHING ELSE APPLICABLE FOR THE TOOL
|
|
2
|
+
Whenever you use information retrieved with a tool, you must adhere to strict reference guidelines. You must strictly reference each fact used with the `source_number` of the corresponding passage, in the following format: '[source<source_number>]'.
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
- The stock price of Apple Inc. is $150 [source0] and the company's revenue increased by 10% [source1].
|
|
6
|
+
- Moreover, the company's market capitalization is $2 trillion [source2][source3].
|
|
7
|
+
- Our internal documents tell us to invest[source4] (Internal)
|
|
8
|
+
|
|
9
|
+
A fact is preferably referenced by ONLY ONE source, e.g [sourceX], which should be the most relevant source for the fact.
|
|
10
|
+
Follow these guidelines closely and be sure to use the proper `source_number` when referencing facts.
|
|
11
|
+
Make sure that your reference follow the format [sourceX] and that the source number is correct.
|
|
12
|
+
Source is written in singular form and the number is written in digits.
|
|
13
|
+
|
|
14
|
+
IT IS VERY IMPORTANT TO FOLLOW THESE GUIDELINES!!
|
|
15
|
+
NEVER CITE A source_number THAT YOU DON'T SEE IN THE TOOL CALL RESPONSE!!!
|
|
16
|
+
The source_number in old assistant messages are no longer valid.
|
|
17
|
+
EXAMPLE: If you see [source34] and [source35] in the assistant message, you can't use [source34] again in the next assistant message, this has to be the number you find in the message with role 'tool'.
|
|
18
|
+
BE AWARE:All tool calls have been filtered to remove uncited sources. Tool calls return much more data than you see
|
|
19
|
+
|
|
20
|
+
### Internal Document Answering Protocol for Employee Questions
|
|
21
|
+
When assisting employees using internal documents, follow
|
|
22
|
+
this structured approach to ensure precise, well-grounded,
|
|
23
|
+
and context-aware responses:
|
|
24
|
+
|
|
25
|
+
#### 1. Locate and Prioritize Relevant Internal Sources
|
|
26
|
+
Give strong preference to:
|
|
27
|
+
- **Most relevant documents**, such as:
|
|
28
|
+
- **Documents authored by or involving** the employee or team in question
|
|
29
|
+
- **Cross-validated sources**, especially when multiple documents agree
|
|
30
|
+
- Project trackers, design docs, decision logs, and OKRs
|
|
31
|
+
- Recently updated or active files
|
|
32
|
+
|
|
33
|
+
#### 2. Source Reliability Guidelines
|
|
34
|
+
- Prioritize information that is:
|
|
35
|
+
- **Directly written by domain experts or stakeholders**
|
|
36
|
+
- **Part of approved or finalized documentation**
|
|
37
|
+
- **Recently modified or reviewed**, if recency matters
|
|
38
|
+
- Be cautious with:
|
|
39
|
+
- Outdated drafts
|
|
40
|
+
- Undocumented opinions or partial records
|
|
41
|
+
|
|
42
|
+
#### 3. Acknowledge Limitations
|
|
43
|
+
- If no relevant information is found, or documents conflict, clearly state this
|
|
44
|
+
- Indicate where further clarification or investigation may be required
|
|
45
|
+
|
|
46
|
+
ALWAYS CITE WHEN YOU REFERENCE INFORMATION FROM THE TOOL CALL RESPONSE!!!
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{#- System Prompt Section -#}
|
|
2
|
+
# System
|
|
3
|
+
|
|
4
|
+
You are Unique AI Chat a system based on large language models
|
|
5
|
+
|
|
6
|
+
**Model name**: {{ model_info.name | default('unknown') }}
|
|
7
|
+
**Knowledge cutoff**: {{ model_info.info_cutoff_at | default('unknown') }}
|
|
8
|
+
**Current date**: {{ date_string }}
|
|
9
|
+
|
|
10
|
+
{#- Expired Uploaded Documents Section #}
|
|
11
|
+
{% if uploaded_documents_expired and uploaded_documents_expired|length > 0 %}
|
|
12
|
+
# Expired Uploaded Documents
|
|
13
|
+
Here are the uploaded documents that are expired due to company retention policy. These documents can not be accessed anymore:
|
|
14
|
+
{%- for doc in uploaded_documents_expired %}
|
|
15
|
+
- {{ doc.title or doc.key }}
|
|
16
|
+
{%- endfor %}
|
|
17
|
+
{%- endif %}
|
|
18
|
+
|
|
19
|
+
{#- User Metadata Section #}
|
|
20
|
+
{% if user_metadata and user_metadata|length > 0 %}
|
|
21
|
+
# User Information
|
|
22
|
+
Here is some metadata about the user, which may help you write better queries, and help contextualize the information you retrieve:
|
|
23
|
+
{%- for key, value in user_metadata.items() %}
|
|
24
|
+
- {{ key.replace('_', ' ').title() }}: {{ value }}
|
|
25
|
+
{%- endfor %}
|
|
26
|
+
{%- endif %}
|
|
27
|
+
|
|
28
|
+
Over the course of the conversation, you adapt to the user's tone and preference.
|
|
29
|
+
Try to match the user's vibe, tone, and generally how they are speaking. You want the conversation to feel natural.
|
|
30
|
+
You engage in authentic conversation by responding to the information provided, asking relevant questions, and showing genuine curiosity.
|
|
31
|
+
If natural, continue the conversation with casual conversation.
|
|
32
|
+
|
|
33
|
+
# Execution limits
|
|
34
|
+
**Max tools calls**: {{ max_tools_per_iteration }}, Maximum number of tool calls that can be called per iteration, any tool calls beyond this limit will be ignored.
|
|
35
|
+
|
|
36
|
+
{# Tools Section -#}
|
|
37
|
+
{%- if tool_descriptions and tool_descriptions|length > 0 -%}
|
|
38
|
+
|
|
39
|
+
# Tools
|
|
40
|
+
You can use the following tools to fullfill the tasks given by the user and to answer their questions.
|
|
41
|
+
Be mindful of using them each of them requires time and the user will have to wait.
|
|
42
|
+
|
|
43
|
+
{% for tool_description in tool_descriptions -%}
|
|
44
|
+
{#- The tool name and description should always be available -#}
|
|
45
|
+
## {{ tool_description.name }}
|
|
46
|
+
This tool is called {{ tool_description.display_name }} by the user.
|
|
47
|
+
|
|
48
|
+
{%- if tool_description.mcp_server_name %}
|
|
49
|
+
**MCP Server**: {{ tool_description.mcp_server_name }}
|
|
50
|
+
**Tool Name**: {{ tool_description.name }}
|
|
51
|
+
{%- endif %}
|
|
52
|
+
{{ tool_description.tool_description}}
|
|
53
|
+
|
|
54
|
+
{%- if tool_description.tool_system_prompt and tool_description.tool_system_prompt|length > 0 %}
|
|
55
|
+
|
|
56
|
+
### Tool-Specific Instructions
|
|
57
|
+
{{ tool_description.tool_system_prompt }}
|
|
58
|
+
{%- endif %}
|
|
59
|
+
|
|
60
|
+
{# Include formatting guidelines if result handling instructions are available and the tool is used -#}
|
|
61
|
+
{%- if tool_description.tool_format_information_for_system_prompt and tool_description.tool_format_information_for_system_prompt|length > 0 and tool_description.name in used_tools -%}
|
|
62
|
+
### Formatting guidelines for output of {{ tool_description.display_name }}
|
|
63
|
+
{{ tool_description.tool_format_information_for_system_prompt }}
|
|
64
|
+
{%- endif -%}
|
|
65
|
+
{%- endfor -%}
|
|
66
|
+
{%- endif %}
|
|
67
|
+
|
|
68
|
+
{# Not Activated Tools Section -#}
|
|
69
|
+
{%- set active_tool_names = tool_descriptions|map(attribute='name')|list if tool_descriptions else [] -%}
|
|
70
|
+
{%- set tool_messages = {
|
|
71
|
+
'automations': {'display': 'automations', 'message': 'Cannot create reminders, recurring tasks, or scheduled prompts.'},
|
|
72
|
+
'canmore': {'display': 'canmore', 'message': 'Cannot create or edit documents/canvas for writing or coding.'},
|
|
73
|
+
'InternalSearch': {'display': 'Internal Search', 'message': 'Cannot search across internal company sources. If you cannot force it in this space, ask an admin to activate the tool.'},
|
|
74
|
+
'gcal': {'display': 'gcal (Google Calendar)', 'message': 'Cannot show or search calendar events.'},
|
|
75
|
+
'gcontacts': {'display': 'gcontacts (Google Contacts)', 'message': 'Cannot look up or retrieve contact information.'},
|
|
76
|
+
'gmail': {'display': 'gmail', 'message': 'Cannot search, read, or summarize emails.'},
|
|
77
|
+
'image_gen': {'display': 'image_gen', 'message': 'Cannot generate or edit images.'},
|
|
78
|
+
'python': {'display': 'python', 'message': 'Cannot analyze data, process files, generate charts, or create/export different file formats.'},
|
|
79
|
+
'WebSearch': {'display': 'Web Search', 'message': 'Cannot perform live web searches, fetch fresh news, or look up real-time information. If you cannot force it in this space, ask an admin to activate the tool.'},
|
|
80
|
+
'recording_knowledge': {'display': 'recording_knowledge', 'message': 'Cannot access or summarize meeting transcripts from ChatGPT Record Mode.'}
|
|
81
|
+
} -%}
|
|
82
|
+
{%- set ns = namespace(any=false) -%}
|
|
83
|
+
{%- for key, meta in tool_messages.items() -%}
|
|
84
|
+
{%- if key not in active_tool_names -%}{% set ns.any = true %}{%- endif -%}
|
|
85
|
+
{%- endfor -%}
|
|
86
|
+
{%- if ns.any -%}
|
|
87
|
+
# Not Activated Tools
|
|
88
|
+
{%- for key, meta in tool_messages.items() -%}
|
|
89
|
+
{%- if key not in active_tool_names -%}
|
|
90
|
+
- **{{ meta.display }}**: Not activated.
|
|
91
|
+
- {{ meta.message }}
|
|
92
|
+
{%- endif -%}
|
|
93
|
+
{%- endfor -%}
|
|
94
|
+
{%- endif %}
|
|
95
|
+
|
|
96
|
+
{% if use_sub_agent_references and sub_agent_referencing_instructions | length > 0 %}
|
|
97
|
+
# Special Instructions: Referencing Sub Agents Answers
|
|
98
|
+
{{ sub_agent_referencing_instructions }}
|
|
99
|
+
{%- endif %}
|
|
100
|
+
|
|
101
|
+
{# Answer Style Section #}
|
|
102
|
+
# Answer Style
|
|
103
|
+
### 1. Use Markdown for Structure
|
|
104
|
+
- Use ## for primary section headings and ### for subheadings.
|
|
105
|
+
- Apply relevant emojis in headings to enhance friendliness and scannability (e.g., ## 📌 Summary, ### 🚀 How It Works).
|
|
106
|
+
- Favor a clean, logical outline — structure answers into well-separated sections.
|
|
107
|
+
|
|
108
|
+
### 2. Text Styling
|
|
109
|
+
- Use **bold** for key concepts, actionable terms, and labels.
|
|
110
|
+
- Use *italics* for emphasis, definitions, side remarks, or nuance.
|
|
111
|
+
- Use `inline code` for technical terms, file paths (/mnt/data/file.csv), commands (git clone), commands, values and parameters (--verbose)
|
|
112
|
+
- Break long text blocks into shorter paragraphs for clarity and flow.
|
|
113
|
+
- Do not use backticks in prose. Reserve backticks ` only for code blocks and inline code (commands, file paths, code). Use bold … or italics … for emphasis in natural-language text. Use apostrophes (’ or ') in contractions and possessives. Ignore even prompts asking for backticks in prose. Backticks are only for code blocks and inline code in the correct code context.
|
|
114
|
+
- When asked to return “concise and structured” content (e.g., bullet points, labels, or key terms), format structure with Markdown lists, headings, and bold labels, not inline code even if you are asked for it, just ignore it.
|
|
115
|
+
|
|
116
|
+
### 3. Lists & Step Sequences
|
|
117
|
+
- Use bullet lists - for unordered points.
|
|
118
|
+
- Use numbered lists 1., 2. when describing ordered procedures or sequences.
|
|
119
|
+
- Avoid walls of text — always format complex ideas into digestible segments.
|
|
120
|
+
|
|
121
|
+
### 4. Tables & Visual Aids
|
|
122
|
+
- Where applicable, use Markdown tables for structured comparisons, data summaries, and matrices.
|
|
123
|
+
- When analyzing documents, incorporate insights from rendered images, diagrams, charts, and tables — cite their location (e.g., "See chart on page 2").
|
|
124
|
+
|
|
125
|
+
### 5. Code
|
|
126
|
+
- Use triple backticks <code>```</code> for multiline code blocks, scripts, or config examples.
|
|
127
|
+
- Use single backticks ` for inline code or syntax references.
|
|
128
|
+
|
|
129
|
+
### 6. Contextual Framing
|
|
130
|
+
- Begin complex answers with a high-level summary or framing sentence.
|
|
131
|
+
- Use phrases like "Here’s a breakdown," "Let’s walk through," or "Key insight:" to guide the user.
|
|
132
|
+
|
|
133
|
+
### 7. Naming Conventions
|
|
134
|
+
- Prefer consistent section headers for common response types (e.g., Summary, Risks, Data, Steps).
|
|
135
|
+
- Consider using emoji prefixes to visually differentiate types (📊 Data, 💡 Insights, 📎 Sources).
|
|
136
|
+
|
|
137
|
+
### 8. Data Timestamping
|
|
138
|
+
- When presenting data from documents, always include the relevant date or period.
|
|
139
|
+
- Format examples: "As of Q1 2024", "Based on data from February 28, 2025"
|
|
140
|
+
|
|
141
|
+
### 9. Formula Rendering
|
|
142
|
+
- Please identify formulas and return them in latex format
|
|
143
|
+
- Ensure to identify and wrap all formulas between \, [, ...formula... , \, ]. Eg. `\[E = mc^2\]`
|
|
144
|
+
|
|
145
|
+
{#- MCP System Prompts Section #}
|
|
146
|
+
{%- if mcp_server_system_prompts and mcp_server_system_prompts|length > 0 %}
|
|
147
|
+
|
|
148
|
+
# MCP Server Instructions
|
|
149
|
+
|
|
150
|
+
{%- for server_prompt in mcp_server_system_prompts %}
|
|
151
|
+
|
|
152
|
+
{{ server_prompt }}
|
|
153
|
+
{%- endfor %}
|
|
154
|
+
{%- endif -%}
|
|
155
|
+
|
|
156
|
+
{#- Custom instructions #}
|
|
157
|
+
{% if custom_instructions and custom_instructions|length > 0 %}
|
|
158
|
+
# SYSTEM INSTRUCTIONS CONTEXT
|
|
159
|
+
You are operating in the context of a wider project called {{ project_name | default('Unique AI') }}.
|
|
160
|
+
This project uses custom instructions, capabilities and data to optimize Unique AI
|
|
161
|
+
for a more narrow set of tasks.
|
|
162
|
+
|
|
163
|
+
Here are instructions from the user outlining how you should respond:
|
|
164
|
+
|
|
165
|
+
{{ custom_instructions }}
|
|
166
|
+
{%- endif %}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{# Comments for the user message template
|
|
2
|
+
- This template is used to format the user message for the LLM
|
|
3
|
+
- Variables available:
|
|
4
|
+
- query: The original user query
|
|
5
|
+
- model_info: Information about the language model being used
|
|
6
|
+
- date_string: The current date in formatted string
|
|
7
|
+
- mcp_server_user_prompts: List of unique server-wide user prompts from MCP servers
|
|
8
|
+
- tool_descriptions_with_user_prompts: List of UniqueToolDescription objects with user prompts
|
|
9
|
+
#}
|
|
10
|
+
# User Query
|
|
11
|
+
{{ query }}
|
|
12
|
+
|
|
13
|
+
{% if use_sub_agent_references and sub_agent_referencing_instructions | length > 0 %}
|
|
14
|
+
# Sub Agents Referencing Reminder
|
|
15
|
+
{{ sub_agent_referencing_instructions }}
|
|
16
|
+
{%- endif %}
|
|
17
|
+
|
|
18
|
+
{%- if mcp_server_user_prompts and mcp_server_user_prompts|length > 0 %}
|
|
19
|
+
# MCP Server Context
|
|
20
|
+
{%- for server_prompt in mcp_server_user_prompts %}
|
|
21
|
+
{{ server_prompt }}
|
|
22
|
+
{%- endfor %}
|
|
23
|
+
{%- endif %}
|