rasa-pro 3.14.0rc1__py3-none-any.whl → 3.14.0rc3__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 rasa-pro might be problematic. Click here for more details.
- rasa/agents/protocol/a2a/a2a_agent.py +50 -42
- rasa/agents/utils.py +27 -5
- rasa/agents/validation.py +7 -9
- rasa/api.py +1 -2
- rasa/builder/copilot/constants.py +4 -1
- rasa/builder/copilot/copilot.py +191 -79
- rasa/builder/copilot/models.py +306 -116
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +33 -12
- rasa/builder/copilot/prompts/copilot_training_error_handler_prompt.jinja2 +53 -0
- rasa/builder/copilot/prompts/latest_user_message_context_prompt.jinja2 +59 -29
- rasa/builder/copilot/telemetry.py +8 -0
- rasa/builder/guardrails/policy_checker.py +1 -1
- rasa/builder/jobs.py +182 -12
- rasa/builder/models.py +12 -3
- rasa/builder/service.py +16 -2
- rasa/cli/dialogue_understanding_test.py +1 -0
- rasa/cli/e2e_test.py +1 -0
- rasa/cli/inspect.py +1 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/help.yml +8 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/human_handoff.yml +41 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/patterns.yml +32 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/show_faqs.yml +8 -0
- rasa/cli/project_templates/finance/domain/general/help.yml +0 -0
- rasa/cli/project_templates/telco/data/network/flow_solve_internet_issue.yml +2 -2
- rasa/cli/project_templates/telco/domain/network/solve_internet_issue.yml +1 -2
- rasa/cli/project_templates/telco/tests/e2e_test_cases/with_stub/network/solve_internet_not_slow.yml +33 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/with_stub/network/solve_internet_slow.yml +47 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
- rasa/cli/run.py +1 -5
- rasa/cli/shell.py +1 -0
- rasa/cli/train.py +1 -0
- rasa/cli/validation/bot_config.py +7 -2
- rasa/core/available_agents.py +65 -55
- rasa/core/brokers/kafka.py +5 -1
- rasa/core/concurrent_lock_store.py +38 -21
- rasa/core/config/available_endpoints.py +0 -3
- rasa/core/config/configuration.py +36 -1
- rasa/core/constants.py +6 -0
- rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +69 -4
- rasa/core/iam_credentials_providers/credentials_provider_protocol.py +2 -1
- rasa/core/lock_store.py +4 -0
- rasa/core/policies/flows/agent_executor.py +16 -8
- rasa/core/redis_connection_factory.py +7 -2
- rasa/core/tracker_stores/redis_tracker_store.py +4 -0
- rasa/core/tracker_stores/sql_tracker_store.py +3 -1
- rasa/dialogue_understanding/commands/start_flow_command.py +10 -3
- rasa/dialogue_understanding/commands/utils.py +15 -4
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +4 -2
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +4 -4
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +4 -4
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +2 -2
- rasa/dialogue_understanding_test/du_test_runner.py +2 -2
- rasa/e2e_test/e2e_test_runner.py +2 -2
- rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +10 -4
- rasa/shared/agents/auth/constants.py +1 -0
- rasa/shared/core/flows/steps/call.py +2 -2
- rasa/telemetry.py +3 -3
- rasa/validator.py +37 -0
- rasa/version.py +1 -1
- {rasa_pro-3.14.0rc1.dist-info → rasa_pro-3.14.0rc3.dist-info}/METADATA +14 -2
- {rasa_pro-3.14.0rc1.dist-info → rasa_pro-3.14.0rc3.dist-info}/RECORD +83 -73
- rasa/cli/project_templates/telco/tests/e2e_test_cases/network/solve_internet_issue.yml +0 -57
- /rasa/cli/project_templates/{finance/tests/e2e_test_cases → basic/tests/e2e_test_cases/without_stub}/general/hello.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{accounts → without_stub/accounts}/check_balance.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{accounts → without_stub/accounts}/download_statements.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{cards → without_stub/cards}/block_card.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{general → without_stub/general}/bot_challenge.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{general → without_stub/general}/feedback.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{general → without_stub/general}/goodbye.yml +0 -0
- /rasa/cli/project_templates/{telco/tests/e2e_test_cases → finance/tests/e2e_test_cases/without_stub}/general/hello.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{general → without_stub/general}/human_handoff.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{general → without_stub/general}/patterns.yml +0 -0
- /rasa/cli/project_templates/finance/tests/e2e_test_cases/{transfers → without_stub/transfers}/transfer_money.yml +0 -0
- /rasa/cli/project_templates/telco/tests/e2e_test_cases/{billing → without_stub/billing}/understand_bill.yml +0 -0
- /rasa/cli/project_templates/telco/tests/e2e_test_cases/{general → without_stub/general}/bot_challenge.yml +0 -0
- /rasa/cli/project_templates/telco/tests/e2e_test_cases/{general → without_stub/general}/feedback.yml +0 -0
- /rasa/cli/project_templates/telco/tests/e2e_test_cases/{general → without_stub/general}/goodbye.yml +0 -0
- /rasa/cli/project_templates/telco/tests/e2e_test_cases/{general → without_stub/general}/human_handoff.yml +0 -0
- /rasa/cli/project_templates/telco/tests/e2e_test_cases/{general → without_stub/general}/patterns.yml +0 -0
- {rasa_pro-3.14.0rc1.dist-info → rasa_pro-3.14.0rc3.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0rc1.dist-info → rasa_pro-3.14.0rc3.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0rc1.dist-info → rasa_pro-3.14.0rc3.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Task
|
|
2
|
+
Your task is to help the user fix a training error that occurred when they clicked the
|
|
3
|
+
"Apply Changes" button. The user made changes to their assistant project files and tried
|
|
4
|
+
to apply them, but the training process failed. You must always explain the error within
|
|
5
|
+
the context of the user's **assistant project files** (flows, domain, actions, config).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Response guidelines
|
|
10
|
+
|
|
11
|
+
1. **Summary** - Start with one short sentence that explains what happened in plain language.
|
|
12
|
+
2. **Explanation** - Describe why this error occurs in Rasa Assistant, focusing only on
|
|
13
|
+
assistant project files. Be precise but simple. Do not speculate or reference Rasa
|
|
14
|
+
internals unrelated to project files.
|
|
15
|
+
3. **Fix Steps** - Provide clear, numbered instructions.
|
|
16
|
+
- Point to specific files (`flows.yml`, `domain.yml`, `actions.py`, etc.).
|
|
17
|
+
- Include corrected YAML or Python snippets if needed.
|
|
18
|
+
- Validate syntax and indentation.
|
|
19
|
+
- Reference documentation for configuration options, syntax rules, or best practices.
|
|
20
|
+
4. **Validation** - End with one line suggesting how to re-test
|
|
21
|
+
5. **Multiple Errors** - If multiple error logs are present, you **must** address and
|
|
22
|
+
propose fixes for **all of them**, not just one.
|
|
23
|
+
|
|
24
|
+
# Context
|
|
25
|
+
|
|
26
|
+
## Relevant Documentation
|
|
27
|
+
|
|
28
|
+
{% if documentation_results %}
|
|
29
|
+
The following documentation sources are available for reference. Use the source index
|
|
30
|
+
numbers (1, 2, 3, etc.) for inline citations when explaining Rasa concepts or providing
|
|
31
|
+
authoritative fixes:
|
|
32
|
+
```
|
|
33
|
+
{{ documentation_results }}
|
|
34
|
+
```
|
|
35
|
+
{% else %}
|
|
36
|
+
No relevant documentation source found.
|
|
37
|
+
{% endif %}
|
|
38
|
+
|
|
39
|
+
## Modified assistant project files
|
|
40
|
+
|
|
41
|
+
{% if modified_files %}
|
|
42
|
+
{{ modified_files }}
|
|
43
|
+
{% else %}
|
|
44
|
+
No modified assistant project files.
|
|
45
|
+
{% endif %}
|
|
46
|
+
|
|
47
|
+
## Available assistant logs
|
|
48
|
+
|
|
49
|
+
{% if logs %}
|
|
50
|
+
{{ logs }}
|
|
51
|
+
{% else %}
|
|
52
|
+
No assistant logs available.
|
|
53
|
+
{% endif %}
|
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
# Context
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Context Priority
|
|
2
|
+
When interpreting user questions (especially vague ones like *"What's this?"*), follow
|
|
3
|
+
this order of priority:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
| Priority | Context Source | Usage |
|
|
6
|
+
|----------|----------------|-------|
|
|
7
|
+
| 1 | **Attachments** | Highest priority. If attachments exist, assume the user's question refers to them. Always ground explanations in attachment content first. |
|
|
8
|
+
| 2 | **Assistant State / Current Conversation** | Use this when attachments are not present. Supplement attachment knowledge with state info if needed. |
|
|
9
|
+
| 3 | **Assistant Files** | Use when neither attachments nor state provide enough context. |
|
|
10
|
+
| 4 | **Documentation Results** | Use to explain Rasa features and validate facts. Must always be cited inline. |
|
|
11
|
+
| 5 | **Assistant Logs** | Lowest priority. Use only if directly relevant to the user’s issue. |
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
```json
|
|
10
|
-
{{ current_conversation }}
|
|
11
|
-
```
|
|
13
|
+
---
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
# Remember!
|
|
16
|
+
- Focus on accessibility and efficiency. Give guidance users can act on right away.
|
|
17
|
+
- Keep answers concise, cut any fluff.
|
|
18
|
+
- Never impersonate or role-play as the assistant being built. You are the **Rasa assistant development expert**.
|
|
19
|
+
- Cite documentation inline frequently — every factual statement about Rasa features, concepts, or capabilities MUST be cited.
|
|
20
|
+
- Only cite from current turn documentation — never from previous conversation turns.
|
|
21
|
+
- NEVER add a separate list of URLs or sources — only use inline citations.
|
|
22
|
+
- NEVER start your response with a ``` or """ or any other quoting characters.
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
***
|
|
24
|
+
---
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
{% endif %}
|
|
26
|
+
# Context Available to You
|
|
27
|
+
Treat everything **below** as context for the user's current request.
|
|
28
|
+
You have access to:
|
|
27
29
|
|
|
30
|
+
***
|
|
28
31
|
|
|
29
32
|
## Assistant Files (Configuration, Domain, Flows)
|
|
30
33
|
{% if assistant_files %}
|
|
@@ -51,11 +54,38 @@ numbers (1, 2, 3, etc.) for inline citations:
|
|
|
51
54
|
No relevant documentation source found.
|
|
52
55
|
{% endif %}
|
|
53
56
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
{% if current_conversation %}
|
|
58
|
+
***
|
|
59
|
+
|
|
60
|
+
## Current Conversation and Conversation State between the user and the assistant
|
|
61
|
+
|
|
62
|
+
**Conversation History:**
|
|
63
|
+
```json
|
|
64
|
+
{{ current_conversation }}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Assistant's State:**
|
|
68
|
+
```json
|
|
69
|
+
{{ current_state }}
|
|
70
|
+
```
|
|
71
|
+
{% endif %}
|
|
72
|
+
|
|
73
|
+
{% if assistant_logs %}
|
|
74
|
+
***
|
|
75
|
+
|
|
76
|
+
## Assistant Logs
|
|
77
|
+
```
|
|
78
|
+
{{ assistant_logs }}
|
|
79
|
+
```
|
|
80
|
+
{% endif %}
|
|
81
|
+
|
|
82
|
+
{% if attachments %}
|
|
83
|
+
***
|
|
84
|
+
|
|
85
|
+
## Attachments
|
|
86
|
+
The user clicked **Ask Copilot** in the **Inspect Mode** and included additional context
|
|
87
|
+
as attachments:
|
|
88
|
+
```json
|
|
89
|
+
{{ attachments }}
|
|
90
|
+
```
|
|
91
|
+
{% endif %}
|
|
@@ -8,6 +8,7 @@ import structlog
|
|
|
8
8
|
from rasa import telemetry
|
|
9
9
|
from rasa.builder.copilot.constants import COPILOT_SEGMENT_WRITE_KEY_ENV_VAR
|
|
10
10
|
from rasa.builder.copilot.copilot_response_handler import CopilotResponseHandler
|
|
11
|
+
from rasa.builder.copilot.models import EventContent
|
|
11
12
|
from rasa.builder.document_retrieval.models import Document
|
|
12
13
|
from rasa.telemetry import (
|
|
13
14
|
SEGMENT_TRACK_ENDPOINT,
|
|
@@ -100,6 +101,7 @@ class CopilotTelemetry:
|
|
|
100
101
|
system_message: Optional[dict[str, Any]] = None,
|
|
101
102
|
chat_history: Optional[list[dict[str, Any]]] = None,
|
|
102
103
|
last_user_message: Optional[str] = None,
|
|
104
|
+
tracker_event_attachments: Optional[list[dict[str, Any]]] = None,
|
|
103
105
|
) -> None:
|
|
104
106
|
"""Track a copilot message in the conversation.
|
|
105
107
|
|
|
@@ -115,6 +117,7 @@ class CopilotTelemetry:
|
|
|
115
117
|
system_message: The system message used (optional).
|
|
116
118
|
chat_history: The chat history messages used (optional).
|
|
117
119
|
last_user_message: The last user message used (optional).
|
|
120
|
+
tracker_event_attachments: The tracker event attachments used (optional).
|
|
118
121
|
"""
|
|
119
122
|
structlogger.debug("builder.telemetry.log_copilot_turn", text=text)
|
|
120
123
|
|
|
@@ -136,6 +139,7 @@ class CopilotTelemetry:
|
|
|
136
139
|
"total_tokens": total_tokens,
|
|
137
140
|
"chat_history": chat_history,
|
|
138
141
|
"last_user_message": last_user_message,
|
|
142
|
+
"tracker_event_attachments": tracker_event_attachments,
|
|
139
143
|
"timestamp": dt.datetime.utcnow().isoformat(),
|
|
140
144
|
}
|
|
141
145
|
|
|
@@ -194,6 +198,7 @@ class CopilotTelemetry:
|
|
|
194
198
|
system_message: dict[str, Any],
|
|
195
199
|
chat_history: list[dict[str, Any]],
|
|
196
200
|
last_user_message: Optional[str],
|
|
201
|
+
tracker_event_attachments: list[EventContent],
|
|
197
202
|
) -> None:
|
|
198
203
|
"""Log a copilot message from the response handler.
|
|
199
204
|
|
|
@@ -223,4 +228,7 @@ class CopilotTelemetry:
|
|
|
223
228
|
system_message=system_message,
|
|
224
229
|
chat_history=chat_history,
|
|
225
230
|
last_user_message=last_user_message,
|
|
231
|
+
tracker_event_attachments=[
|
|
232
|
+
attachment.model_dump() for attachment in tracker_event_attachments
|
|
233
|
+
],
|
|
226
234
|
)
|
|
@@ -315,7 +315,7 @@ class GuardrailsPolicyChecker:
|
|
|
315
315
|
continue
|
|
316
316
|
if message.role != ROLE_USER:
|
|
317
317
|
continue
|
|
318
|
-
formatted_message = message.
|
|
318
|
+
formatted_message = message.build_openai_message()
|
|
319
319
|
text = (formatted_message.get("content") or "").strip()
|
|
320
320
|
if not text:
|
|
321
321
|
continue
|
rasa/builder/jobs.py
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
from typing import Any, Optional
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
2
|
|
|
3
3
|
import structlog
|
|
4
4
|
from sanic import Sanic
|
|
5
5
|
|
|
6
6
|
from rasa.builder import config
|
|
7
|
+
from rasa.builder.copilot.models import (
|
|
8
|
+
CopilotContext,
|
|
9
|
+
FileContent,
|
|
10
|
+
InternalCopilotRequestChatMessage,
|
|
11
|
+
LogContent,
|
|
12
|
+
ResponseCategory,
|
|
13
|
+
TrainingErrorLog,
|
|
14
|
+
)
|
|
7
15
|
from rasa.builder.exceptions import (
|
|
8
16
|
LLMGenerationError,
|
|
9
17
|
ProjectGenerationError,
|
|
@@ -11,6 +19,7 @@ from rasa.builder.exceptions import (
|
|
|
11
19
|
ValidationError,
|
|
12
20
|
)
|
|
13
21
|
from rasa.builder.job_manager import JobInfo, job_manager
|
|
22
|
+
from rasa.builder.llm_service import llm_service
|
|
14
23
|
from rasa.builder.models import (
|
|
15
24
|
JobStatus,
|
|
16
25
|
JobStatusEvent,
|
|
@@ -28,9 +37,14 @@ structlogger = structlog.get_logger()
|
|
|
28
37
|
|
|
29
38
|
|
|
30
39
|
async def push_job_status_event(
|
|
31
|
-
job: JobInfo,
|
|
40
|
+
job: JobInfo,
|
|
41
|
+
status: JobStatus,
|
|
42
|
+
message: Optional[str] = None,
|
|
43
|
+
payload: Optional[Dict[str, Any]] = None,
|
|
32
44
|
) -> None:
|
|
33
|
-
event = JobStatusEvent.from_status(
|
|
45
|
+
event = JobStatusEvent.from_status(
|
|
46
|
+
status=status.value, message=message, payload=payload
|
|
47
|
+
)
|
|
34
48
|
job.status = status.value
|
|
35
49
|
await job.put(event)
|
|
36
50
|
|
|
@@ -210,7 +224,7 @@ async def run_template_to_bot_job(
|
|
|
210
224
|
async def run_replace_all_files_job(
|
|
211
225
|
app: "Sanic",
|
|
212
226
|
job: JobInfo,
|
|
213
|
-
bot_files:
|
|
227
|
+
bot_files: Dict[str, Any],
|
|
214
228
|
) -> None:
|
|
215
229
|
"""Run the replace-all-files job in the background.
|
|
216
230
|
|
|
@@ -228,7 +242,7 @@ async def run_replace_all_files_job(
|
|
|
228
242
|
try:
|
|
229
243
|
project_generator.replace_all_bot_files(bot_files)
|
|
230
244
|
|
|
231
|
-
#
|
|
245
|
+
# Validating
|
|
232
246
|
await push_job_status_event(job, JobStatus.validating)
|
|
233
247
|
training_input = project_generator.get_training_input()
|
|
234
248
|
validation_error = await validate_project(training_input.importer)
|
|
@@ -236,12 +250,13 @@ async def run_replace_all_files_job(
|
|
|
236
250
|
raise ValidationError(validation_error)
|
|
237
251
|
await push_job_status_event(job, JobStatus.validation_success)
|
|
238
252
|
|
|
239
|
-
#
|
|
253
|
+
# Training
|
|
240
254
|
await push_job_status_event(job, JobStatus.training)
|
|
241
255
|
agent = await train_and_load_agent(training_input)
|
|
242
256
|
update_agent(agent, app)
|
|
243
257
|
await push_job_status_event(job, JobStatus.train_success)
|
|
244
258
|
|
|
259
|
+
# Send final done event
|
|
245
260
|
await push_job_status_event(job, JobStatus.done)
|
|
246
261
|
job_manager.mark_done(job)
|
|
247
262
|
|
|
@@ -257,26 +272,181 @@ async def run_replace_all_files_job(
|
|
|
257
272
|
included_log_levels=log_levels,
|
|
258
273
|
)
|
|
259
274
|
error_message = exc.get_error_message_with_logs(log_levels=log_levels)
|
|
260
|
-
|
|
261
|
-
|
|
275
|
+
# Push error event and start copilot analysis job
|
|
276
|
+
await push_error_and_start_copilot_analysis(
|
|
277
|
+
app,
|
|
278
|
+
job,
|
|
279
|
+
JobStatus.validation_error,
|
|
280
|
+
error_message,
|
|
281
|
+
bot_files,
|
|
262
282
|
)
|
|
283
|
+
|
|
284
|
+
# After error mark job as done
|
|
263
285
|
job_manager.mark_done(job, error=error_message)
|
|
264
286
|
|
|
265
287
|
except TrainingError as exc:
|
|
288
|
+
error_message = str(exc)
|
|
266
289
|
structlogger.debug(
|
|
267
290
|
"replace_all_files_job.train_error",
|
|
268
291
|
job_id=job.id,
|
|
269
|
-
error=
|
|
292
|
+
error=error_message,
|
|
270
293
|
)
|
|
271
|
-
|
|
272
|
-
|
|
294
|
+
# Push error event and start copilot analysis job
|
|
295
|
+
await push_error_and_start_copilot_analysis(
|
|
296
|
+
app,
|
|
297
|
+
job,
|
|
298
|
+
JobStatus.train_error,
|
|
299
|
+
error_message,
|
|
300
|
+
bot_files,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# After error mark job as done
|
|
304
|
+
job_manager.mark_done(job, error=error_message)
|
|
273
305
|
|
|
274
306
|
except Exception as exc:
|
|
275
307
|
# Capture full traceback for anything truly unexpected
|
|
308
|
+
error_message = str(exc)
|
|
276
309
|
structlogger.exception(
|
|
277
310
|
"replace_all_files_job.unexpected_error",
|
|
278
311
|
job_id=job.id,
|
|
312
|
+
error=error_message,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# Push error event and start copilot analysis job
|
|
316
|
+
await push_error_and_start_copilot_analysis(
|
|
317
|
+
app,
|
|
318
|
+
job,
|
|
319
|
+
JobStatus.error,
|
|
320
|
+
error_message,
|
|
321
|
+
bot_files,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
# After error mark job as done
|
|
325
|
+
job_manager.mark_done(job, error=str(exc))
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
async def push_error_and_start_copilot_analysis(
|
|
329
|
+
app: "Sanic",
|
|
330
|
+
original_job: JobInfo,
|
|
331
|
+
original_job_status: JobStatus,
|
|
332
|
+
error_message: str,
|
|
333
|
+
bot_files: Dict[str, Any],
|
|
334
|
+
) -> None:
|
|
335
|
+
"""Start a copilot analysis job and notify the client.
|
|
336
|
+
|
|
337
|
+
Creates a copilot analysis job and sends the new job ID to the client. The new
|
|
338
|
+
job runs in the background.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
app: The Sanic application instance
|
|
342
|
+
original_job: The original job that failed
|
|
343
|
+
original_job_status: The status of the job that failed
|
|
344
|
+
error_message: The error message to analyze
|
|
345
|
+
bot_files: The bot files to include in analysis
|
|
346
|
+
"""
|
|
347
|
+
# Create a copilot analysis job. Send the new job ID to the client and
|
|
348
|
+
# run the Copilot Analysis job in the background.
|
|
349
|
+
message = "Failed to train the assistant. Starting copilot analysis."
|
|
350
|
+
|
|
351
|
+
copilot_job = job_manager.create_job()
|
|
352
|
+
# Push the error status event for the original job
|
|
353
|
+
await push_job_status_event(
|
|
354
|
+
original_job,
|
|
355
|
+
original_job_status,
|
|
356
|
+
message=message,
|
|
357
|
+
payload={"copilot_job_id": copilot_job.id},
|
|
358
|
+
)
|
|
359
|
+
# Run the copilot analysis job in the background
|
|
360
|
+
app.add_task(
|
|
361
|
+
run_copilot_training_error_analysis_job(
|
|
362
|
+
app, copilot_job, error_message, bot_files
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
structlogger.debug(
|
|
366
|
+
f"update_files_job.{original_job_status.value}.copilot_analysis_start",
|
|
367
|
+
event_info=message,
|
|
368
|
+
job_id=original_job.id,
|
|
369
|
+
error=error_message,
|
|
370
|
+
copilot_job_id=copilot_job.id,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
async def run_copilot_training_error_analysis_job(
|
|
375
|
+
app: "Sanic",
|
|
376
|
+
job: JobInfo,
|
|
377
|
+
training_error_message: str,
|
|
378
|
+
bot_files: Dict[str, Any],
|
|
379
|
+
) -> None:
|
|
380
|
+
"""Run copilot training error analysis job."""
|
|
381
|
+
await push_job_status_event(job, JobStatus.received)
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
# Create message content blocks with log content and available files
|
|
385
|
+
log_content_block = LogContent(
|
|
386
|
+
type="log", content=training_error_message, context="training_error"
|
|
387
|
+
)
|
|
388
|
+
file_content_blocks = [
|
|
389
|
+
FileContent(type="file", file_path=file_path, file_content=file_content)
|
|
390
|
+
for file_path, file_content in bot_files.items()
|
|
391
|
+
]
|
|
392
|
+
context = CopilotContext(
|
|
393
|
+
tracker_context=None, # No conversation context needed
|
|
394
|
+
copilot_chat_history=[
|
|
395
|
+
InternalCopilotRequestChatMessage(
|
|
396
|
+
role="internal_copilot_request",
|
|
397
|
+
content=[log_content_block, *file_content_blocks],
|
|
398
|
+
response_category=ResponseCategory.TRAINING_ERROR_LOG_ANALYSIS,
|
|
399
|
+
)
|
|
400
|
+
],
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
# Generate copilot response
|
|
404
|
+
copilot_client = llm_service.instantiate_copilot()
|
|
405
|
+
(
|
|
406
|
+
original_stream,
|
|
407
|
+
generation_context,
|
|
408
|
+
) = await copilot_client.generate_response(context)
|
|
409
|
+
|
|
410
|
+
copilot_response_handler = llm_service.instantiate_handler(
|
|
411
|
+
config.COPILOT_HANDLER_ROLLING_BUFFER_SIZE
|
|
412
|
+
)
|
|
413
|
+
intercepted_stream = copilot_response_handler.handle_response(original_stream)
|
|
414
|
+
|
|
415
|
+
# Stream the copilot response as job events
|
|
416
|
+
async for token in intercepted_stream:
|
|
417
|
+
# Send each token as a job event using the same format as /copilot endpoint
|
|
418
|
+
await push_job_status_event(
|
|
419
|
+
job, JobStatus.copilot_analyzing, payload=token.sse_data
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
# Send references (if any) as part of copilot_analyzing stream
|
|
423
|
+
if generation_context.relevant_documents:
|
|
424
|
+
reference_section = copilot_response_handler.extract_references(
|
|
425
|
+
generation_context.relevant_documents
|
|
426
|
+
)
|
|
427
|
+
await push_job_status_event(
|
|
428
|
+
job, JobStatus.copilot_analyzing, payload=reference_section.sse_data
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
# Send original error log as part of copilot_analyzing stream
|
|
432
|
+
training_error_log = TrainingErrorLog(logs=[log_content_block])
|
|
433
|
+
await push_job_status_event(
|
|
434
|
+
job, JobStatus.copilot_analyzing, payload=training_error_log.sse_data
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
# Send success status
|
|
438
|
+
await push_job_status_event(job, JobStatus.copilot_analysis_success)
|
|
439
|
+
|
|
440
|
+
await push_job_status_event(job, JobStatus.done)
|
|
441
|
+
job_manager.mark_done(job)
|
|
442
|
+
|
|
443
|
+
except Exception as exc:
|
|
444
|
+
structlogger.exception(
|
|
445
|
+
"copilot_training_error_analysis_job.error",
|
|
446
|
+
job_id=job.id,
|
|
279
447
|
error=str(exc),
|
|
280
448
|
)
|
|
281
|
-
await push_job_status_event(
|
|
449
|
+
await push_job_status_event(
|
|
450
|
+
job, JobStatus.copilot_analysis_error, message=str(exc)
|
|
451
|
+
)
|
|
282
452
|
job_manager.mark_done(job, error=str(exc))
|
rasa/builder/models.py
CHANGED
|
@@ -136,12 +136,14 @@ class JobStatusEvent(ServerSentEvent):
|
|
|
136
136
|
cls,
|
|
137
137
|
status: str,
|
|
138
138
|
message: Optional[str] = None,
|
|
139
|
+
payload: Optional[Dict[str, Any]] = None,
|
|
139
140
|
) -> "JobStatusEvent":
|
|
140
141
|
"""Factory for job-status events.
|
|
141
142
|
|
|
142
143
|
Args:
|
|
143
144
|
status: The job status (e.g. "training", "train_success").
|
|
144
145
|
message: Optional error message for error events.
|
|
146
|
+
payload: Optional additional payload data to include in the event.
|
|
145
147
|
|
|
146
148
|
Returns:
|
|
147
149
|
A JobStatusEvent instance with the appropriate event type and data.
|
|
@@ -150,11 +152,13 @@ class JobStatusEvent(ServerSentEvent):
|
|
|
150
152
|
ServerSentEventType.error if message else ServerSentEventType.progress
|
|
151
153
|
)
|
|
152
154
|
|
|
153
|
-
|
|
155
|
+
event_payload: Dict[str, Any] = {"status": status}
|
|
154
156
|
if message:
|
|
155
|
-
|
|
157
|
+
event_payload["message"] = message
|
|
158
|
+
if payload:
|
|
159
|
+
event_payload.update(payload)
|
|
156
160
|
|
|
157
|
-
return cls(event=event_type.value, data=
|
|
161
|
+
return cls(event=event_type.value, data=event_payload)
|
|
158
162
|
|
|
159
163
|
|
|
160
164
|
class ValidationResult(BaseModel):
|
|
@@ -193,6 +197,11 @@ class JobStatus(str, Enum):
|
|
|
193
197
|
validation_success = "validation_success"
|
|
194
198
|
validation_error = "validation_error"
|
|
195
199
|
|
|
200
|
+
copilot_analysis_start = "copilot_analysis_start"
|
|
201
|
+
copilot_analyzing = "copilot_analyzing"
|
|
202
|
+
copilot_analysis_success = "copilot_analysis_success"
|
|
203
|
+
copilot_analysis_error = "copilot_analysis_error"
|
|
204
|
+
|
|
196
205
|
|
|
197
206
|
class JobCreateResponse(BaseModel):
|
|
198
207
|
job_id: str = Field(...)
|
rasa/builder/service.py
CHANGED
|
@@ -532,7 +532,19 @@ async def get_bot_files(request: Request) -> HTTPResponse:
|
|
|
532
532
|
"**Error Events (can occur at any time):**\n"
|
|
533
533
|
"- `validation_error` - Bot configuration files are invalid\n"
|
|
534
534
|
"- `train_error` - Files updated but training failed\n"
|
|
535
|
+
"- `copilot_analysis_start` - Copilot analysis started (includes `copilot_job_id` "
|
|
536
|
+
"in payload)\n"
|
|
535
537
|
"- `error` - Unexpected error occurred\n\n"
|
|
538
|
+
"**Copilot Analysis Events:**\n"
|
|
539
|
+
"When training or validation fails, a separate copilot analysis job is "
|
|
540
|
+
"automatically started. The `copilot_analysis_start` event includes a "
|
|
541
|
+
"`copilot_job_id` in the payload.\nConnect to `/job-events/<copilot_job_id>` to "
|
|
542
|
+
"receive the following events:\n"
|
|
543
|
+
"- `copilot_analyzing` - Copilot is analyzing errors and providing suggestions. "
|
|
544
|
+
"Uses the same SSE event payload format as the `/copilot` endpoint with `content`, "
|
|
545
|
+
"`response_category`, and `completeness` fields.\n"
|
|
546
|
+
"- `copilot_analysis_success` - Copilot analysis completed with references.\n"
|
|
547
|
+
"- `copilot_analysis_error` - Copilot analysis failed\n\n"
|
|
536
548
|
"**Usage:**\n"
|
|
537
549
|
"1. Send POST request with Content-Type: application/json\n"
|
|
538
550
|
"2. The response will be a JSON object `{job_id: ...}`\n"
|
|
@@ -1042,7 +1054,8 @@ async def copilot(request: Request) -> None:
|
|
|
1042
1054
|
# Offload telemetry logging to a background task
|
|
1043
1055
|
request.app.add_task(
|
|
1044
1056
|
asyncio.to_thread(
|
|
1045
|
-
telemetry.log_user_turn,
|
|
1057
|
+
telemetry.log_user_turn,
|
|
1058
|
+
req.last_message.get_flattened_text_content(),
|
|
1046
1059
|
)
|
|
1047
1060
|
)
|
|
1048
1061
|
|
|
@@ -1159,10 +1172,11 @@ async def copilot(request: Request) -> None:
|
|
|
1159
1172
|
system_message=generation_context.system_message,
|
|
1160
1173
|
chat_history=generation_context.chat_history,
|
|
1161
1174
|
last_user_message=(
|
|
1162
|
-
req.last_message.
|
|
1175
|
+
req.last_message.get_flattened_text_content()
|
|
1163
1176
|
if (req.last_message and req.last_message.role == ROLE_USER)
|
|
1164
1177
|
else None
|
|
1165
1178
|
),
|
|
1179
|
+
tracker_event_attachments=generation_context.tracker_event_attachments,
|
|
1166
1180
|
**copilot_client.usage_statistics.model_dump(),
|
|
1167
1181
|
)
|
|
1168
1182
|
)
|
|
@@ -214,6 +214,7 @@ def execute_dialogue_understanding_tests(args: argparse.Namespace) -> None:
|
|
|
214
214
|
|
|
215
215
|
# initialization of endpoints
|
|
216
216
|
endpoints = set_up_available_endpoints(args)
|
|
217
|
+
Configuration.initialise_sub_agents(args.sub_agents)
|
|
217
218
|
|
|
218
219
|
# set up the test runner, e.g. start the agent
|
|
219
220
|
try:
|
rasa/cli/e2e_test.py
CHANGED
|
@@ -160,6 +160,7 @@ def execute_e2e_tests(args: argparse.Namespace) -> None:
|
|
|
160
160
|
endpoints = Configuration.initialise_endpoints(
|
|
161
161
|
endpoints_path=EndpointsConfigPath.validate(args.endpoints)
|
|
162
162
|
).endpoints
|
|
163
|
+
Configuration.initialise_sub_agents(args.sub_agents)
|
|
163
164
|
|
|
164
165
|
# Ignore all endpoints apart from action server, model, nlu and nlg
|
|
165
166
|
# to ensure InMemoryTrackerStore is being used instead of production
|
rasa/cli/inspect.py
CHANGED
|
@@ -93,6 +93,7 @@ def inspect(args: argparse.Namespace) -> None:
|
|
|
93
93
|
# it can be used safely throughout the codebase with
|
|
94
94
|
# `Configuration.get_instance().endpoints`
|
|
95
95
|
Configuration.initialise_endpoints(endpoints_path=Path(args.endpoints))
|
|
96
|
+
Configuration.initialise_sub_agents(args.sub_agents)
|
|
96
97
|
|
|
97
98
|
try:
|
|
98
99
|
model = get_local_model(model)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
test_cases:
|
|
2
|
+
- test_case: positive feedback
|
|
3
|
+
steps:
|
|
4
|
+
- user: "goodbye"
|
|
5
|
+
assertions:
|
|
6
|
+
- flow_started: "goodbye_flow"
|
|
7
|
+
- bot_uttered:
|
|
8
|
+
utter_name: "utter_goodbye"
|
|
9
|
+
- flow_started: "leave_feedback"
|
|
10
|
+
- bot_uttered:
|
|
11
|
+
utter_name: "utter_ask_feedback_rating"
|
|
12
|
+
buttons:
|
|
13
|
+
- title: "👍 Great"
|
|
14
|
+
payload: "/SetSlots(feedback_rating=thumbs_up)"
|
|
15
|
+
- title: "👎 Could be better"
|
|
16
|
+
payload: "/SetSlots(feedback_rating=thumbs_down)"
|
|
17
|
+
- user: "/SetSlots(feedback_rating=thumbs_up)"
|
|
18
|
+
assertions:
|
|
19
|
+
- slot_was_set:
|
|
20
|
+
- name: "feedback_rating"
|
|
21
|
+
value: "thumbs_up"
|
|
22
|
+
- bot_uttered:
|
|
23
|
+
utter_name: "utter_thankyou_positive"
|
|
24
|
+
#
|
|
25
|
+
- test_case: negative feedback
|
|
26
|
+
steps:
|
|
27
|
+
- user: "goodbye"
|
|
28
|
+
assertions:
|
|
29
|
+
- flow_started: "goodbye_flow"
|
|
30
|
+
- bot_uttered:
|
|
31
|
+
utter_name: "utter_goodbye"
|
|
32
|
+
- flow_started: "leave_feedback"
|
|
33
|
+
- bot_uttered:
|
|
34
|
+
utter_name: "utter_ask_feedback_rating"
|
|
35
|
+
buttons:
|
|
36
|
+
- title: "👍 Great"
|
|
37
|
+
payload: "/SetSlots(feedback_rating=thumbs_up)"
|
|
38
|
+
- title: "👎 Could be better"
|
|
39
|
+
payload: "/SetSlots(feedback_rating=thumbs_down)"
|
|
40
|
+
- user: "/SetSlots(feedback_rating=thumbs_down)"
|
|
41
|
+
assertions:
|
|
42
|
+
- slot_was_set:
|
|
43
|
+
- name: "feedback_rating"
|
|
44
|
+
value: "thumbs_down"
|
|
45
|
+
- bot_uttered:
|
|
46
|
+
utter_name: "utter_thankyou_negative"
|