frontend-perception-engine 0.1.2__tar.gz → 0.2.0__tar.gz
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.
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/PKG-INFO +17 -1
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/README.md +15 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/pyproject.toml +2 -1
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/PKG-INFO +17 -1
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/SOURCES.txt +4 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/requires.txt +1 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/cli/install.py +4 -1
- frontend_perception_engine-0.2.0/src/navigation/mcp/diff.py +68 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/envelope.py +19 -10
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/handlers.py +201 -91
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/instructions.py +4 -2
- frontend_perception_engine-0.2.0/src/navigation/mcp/resources.py +108 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/server.py +5 -4
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/tools.py +37 -11
- frontend_perception_engine-0.2.0/src/navigation/mcp/visual_response.py +103 -0
- frontend_perception_engine-0.2.0/src/navigation/perception/observation.py +121 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/scan.py +11 -1
- frontend_perception_engine-0.2.0/src/navigation/perception/visual_capture.py +211 -0
- frontend_perception_engine-0.2.0/src/navigation/perception/visual_diff.py +101 -0
- frontend_perception_engine-0.2.0/src/navigation/perception/visual_insights.py +163 -0
- frontend_perception_engine-0.1.2/src/navigation/mcp/diff.py +0 -28
- frontend_perception_engine-0.1.2/src/navigation/mcp/resources.py +0 -82
- frontend_perception_engine-0.1.2/src/navigation/perception/observation.py +0 -97
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/setup.cfg +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/dependency_links.txt +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/entry_points.txt +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/frontend_perception_engine.egg-info/top_level.txt +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/__init__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/__init__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/agent_runner.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/hints.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/integration.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/browser_use/llm.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/cli/__init__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/__init__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/crg_impl.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/factory.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/interface.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/codeGraph/null_impl.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/__init__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/__main__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/scan_registry.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/session_store.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/__init__.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/artifacts.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/auth_gate.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/budget.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/cdp_hub.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/dev_insights.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/exploration.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/feature_flags.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/file_upload.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/flow_graph.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/form_probe.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/iframe_context.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/preflight.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/rich_editors.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/route_guards.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/runner.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/scripted_actions.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/state_manager.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/verification.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/virtual_scroll.py +0 -0
- {frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/perception/websocket_observer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontend-perception-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Frontend perception engine with optional CRG-powered navigation hints for Browser Use.
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -8,6 +8,7 @@ Requires-Dist: browser-use>=0.13.3
|
|
|
8
8
|
Requires-Dist: code-review-graph>=2.3.6
|
|
9
9
|
Requires-Dist: python-dotenv>=1.0.0
|
|
10
10
|
Requires-Dist: mcp>=1.0.0
|
|
11
|
+
Requires-Dist: pillow>=10.0.0
|
|
11
12
|
Provides-Extra: aws
|
|
12
13
|
Requires-Dist: boto3>=1.35.0; extra == "aws"
|
|
13
14
|
|
|
@@ -55,12 +56,25 @@ Your coding agent (Cursor/Claude/Codex) remains the brain.
|
|
|
55
56
|
|
|
56
57
|
### Install
|
|
57
58
|
|
|
59
|
+
Both PyPI names install the same MCP server:
|
|
60
|
+
|
|
61
|
+
| Package | Install |
|
|
62
|
+
|---------|---------|
|
|
63
|
+
| `frontend-perception-engine` | `pip install frontend-perception-engine` |
|
|
64
|
+
| `frontend-mcp` (alias) | `pip install frontend-mcp` |
|
|
65
|
+
|
|
58
66
|
Recommended (quiet output + next steps):
|
|
59
67
|
|
|
60
68
|
```bash
|
|
61
69
|
uvx --from frontend-perception-engine frontend-perception-install
|
|
62
70
|
```
|
|
63
71
|
|
|
72
|
+
Or the shorter alias name:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uvx --from frontend-mcp frontend-mcp-install
|
|
76
|
+
```
|
|
77
|
+
|
|
64
78
|
With Chromium for Browser Use:
|
|
65
79
|
|
|
66
80
|
```bash
|
|
@@ -97,6 +111,8 @@ Using `uvx` (no local install in current environment):
|
|
|
97
111
|
|
|
98
112
|
```bash
|
|
99
113
|
uvx --from frontend-perception-engine frontend-perception-mcp
|
|
114
|
+
# or
|
|
115
|
+
uvx --from frontend-mcp frontend-mcp
|
|
100
116
|
```
|
|
101
117
|
|
|
102
118
|
### Cursor MCP config
|
|
@@ -42,12 +42,25 @@ Your coding agent (Cursor/Claude/Codex) remains the brain.
|
|
|
42
42
|
|
|
43
43
|
### Install
|
|
44
44
|
|
|
45
|
+
Both PyPI names install the same MCP server:
|
|
46
|
+
|
|
47
|
+
| Package | Install |
|
|
48
|
+
|---------|---------|
|
|
49
|
+
| `frontend-perception-engine` | `pip install frontend-perception-engine` |
|
|
50
|
+
| `frontend-mcp` (alias) | `pip install frontend-mcp` |
|
|
51
|
+
|
|
45
52
|
Recommended (quiet output + next steps):
|
|
46
53
|
|
|
47
54
|
```bash
|
|
48
55
|
uvx --from frontend-perception-engine frontend-perception-install
|
|
49
56
|
```
|
|
50
57
|
|
|
58
|
+
Or the shorter alias name:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uvx --from frontend-mcp frontend-mcp-install
|
|
62
|
+
```
|
|
63
|
+
|
|
51
64
|
With Chromium for Browser Use:
|
|
52
65
|
|
|
53
66
|
```bash
|
|
@@ -84,6 +97,8 @@ Using `uvx` (no local install in current environment):
|
|
|
84
97
|
|
|
85
98
|
```bash
|
|
86
99
|
uvx --from frontend-perception-engine frontend-perception-mcp
|
|
100
|
+
# or
|
|
101
|
+
uvx --from frontend-mcp frontend-mcp
|
|
87
102
|
```
|
|
88
103
|
|
|
89
104
|
### Cursor MCP config
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "frontend-perception-engine"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Frontend perception engine with optional CRG-powered navigation hints for Browser Use."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -9,6 +9,7 @@ dependencies = [
|
|
|
9
9
|
"code-review-graph>=2.3.6",
|
|
10
10
|
"python-dotenv>=1.0.0",
|
|
11
11
|
"mcp>=1.0.0",
|
|
12
|
+
"pillow>=10.0.0",
|
|
12
13
|
]
|
|
13
14
|
|
|
14
15
|
[project.scripts]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontend-perception-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Frontend perception engine with optional CRG-powered navigation hints for Browser Use.
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -8,6 +8,7 @@ Requires-Dist: browser-use>=0.13.3
|
|
|
8
8
|
Requires-Dist: code-review-graph>=2.3.6
|
|
9
9
|
Requires-Dist: python-dotenv>=1.0.0
|
|
10
10
|
Requires-Dist: mcp>=1.0.0
|
|
11
|
+
Requires-Dist: pillow>=10.0.0
|
|
11
12
|
Provides-Extra: aws
|
|
12
13
|
Requires-Dist: boto3>=1.35.0; extra == "aws"
|
|
13
14
|
|
|
@@ -55,12 +56,25 @@ Your coding agent (Cursor/Claude/Codex) remains the brain.
|
|
|
55
56
|
|
|
56
57
|
### Install
|
|
57
58
|
|
|
59
|
+
Both PyPI names install the same MCP server:
|
|
60
|
+
|
|
61
|
+
| Package | Install |
|
|
62
|
+
|---------|---------|
|
|
63
|
+
| `frontend-perception-engine` | `pip install frontend-perception-engine` |
|
|
64
|
+
| `frontend-mcp` (alias) | `pip install frontend-mcp` |
|
|
65
|
+
|
|
58
66
|
Recommended (quiet output + next steps):
|
|
59
67
|
|
|
60
68
|
```bash
|
|
61
69
|
uvx --from frontend-perception-engine frontend-perception-install
|
|
62
70
|
```
|
|
63
71
|
|
|
72
|
+
Or the shorter alias name:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uvx --from frontend-mcp frontend-mcp-install
|
|
76
|
+
```
|
|
77
|
+
|
|
64
78
|
With Chromium for Browser Use:
|
|
65
79
|
|
|
66
80
|
```bash
|
|
@@ -97,6 +111,8 @@ Using `uvx` (no local install in current environment):
|
|
|
97
111
|
|
|
98
112
|
```bash
|
|
99
113
|
uvx --from frontend-perception-engine frontend-perception-mcp
|
|
114
|
+
# or
|
|
115
|
+
uvx --from frontend-mcp frontend-mcp
|
|
100
116
|
```
|
|
101
117
|
|
|
102
118
|
### Cursor MCP config
|
|
@@ -30,6 +30,7 @@ src/navigation/mcp/scan_registry.py
|
|
|
30
30
|
src/navigation/mcp/server.py
|
|
31
31
|
src/navigation/mcp/session_store.py
|
|
32
32
|
src/navigation/mcp/tools.py
|
|
33
|
+
src/navigation/mcp/visual_response.py
|
|
33
34
|
src/navigation/perception/__init__.py
|
|
34
35
|
src/navigation/perception/artifacts.py
|
|
35
36
|
src/navigation/perception/auth_gate.py
|
|
@@ -52,4 +53,7 @@ src/navigation/perception/scripted_actions.py
|
|
|
52
53
|
src/navigation/perception/state_manager.py
|
|
53
54
|
src/navigation/perception/verification.py
|
|
54
55
|
src/navigation/perception/virtual_scroll.py
|
|
56
|
+
src/navigation/perception/visual_capture.py
|
|
57
|
+
src/navigation/perception/visual_diff.py
|
|
58
|
+
src/navigation/perception/visual_insights.py
|
|
55
59
|
src/navigation/perception/websocket_observer.py
|
{frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/cli/install.py
RENAMED
|
@@ -127,7 +127,9 @@ def _print_success(*, with_browser: bool) -> None:
|
|
|
127
127
|
sys.stdout.write(' frontend-perception-mcp\n\n')
|
|
128
128
|
sys.stdout.write(' Or with uvx (no global install):\n')
|
|
129
129
|
sys.stdout.write(' uvx --from frontend-perception-engine frontend-perception-mcp\n\n')
|
|
130
|
-
sys.stdout.write('
|
|
130
|
+
sys.stdout.write(' Or shorter PyPI name:\n')
|
|
131
|
+
sys.stdout.write(' uvx --from frontend-mcp frontend-mcp\n\n')
|
|
132
|
+
sys.stdout.write(' Cursor MCP config (either name):\n')
|
|
131
133
|
sys.stdout.write(' {\n')
|
|
132
134
|
sys.stdout.write(' "mcpServers": {\n')
|
|
133
135
|
sys.stdout.write(' "frontend-perception": {\n')
|
|
@@ -136,6 +138,7 @@ def _print_success(*, with_browser: bool) -> None:
|
|
|
136
138
|
sys.stdout.write(' }\n')
|
|
137
139
|
sys.stdout.write(' }\n')
|
|
138
140
|
sys.stdout.write(' }\n')
|
|
141
|
+
sys.stdout.write('\n Alias package: pip install frontend-mcp → frontend-mcp / frontend-mcp-install\n')
|
|
139
142
|
if with_browser:
|
|
140
143
|
sys.stdout.write('\n Chromium is ready for Browser Use.\n')
|
|
141
144
|
sys.stdout.flush()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Compare two observation snapshots by scan_id."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from navigation.perception.visual_diff import VisualDiffResult, diff_screenshot_files
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _blocking_issues(obs: dict[str, Any]) -> list[str]:
|
|
11
|
+
di = obs.get('dev_insights') or {}
|
|
12
|
+
summary = di.get('summary') or {}
|
|
13
|
+
blocking = list(summary.get('blocking_issues') or [])
|
|
14
|
+
visual = obs.get('visual_insights') or {}
|
|
15
|
+
blocking.extend(visual.get('blocking') or [])
|
|
16
|
+
return blocking
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _visual_issues_delta(before: dict[str, Any], after: dict[str, Any]) -> dict[str, list[str]]:
|
|
20
|
+
b_vis = set((before.get('visual_insights') or {}).get('blocking') or [])
|
|
21
|
+
a_vis = set((after.get('visual_insights') or {}).get('blocking') or [])
|
|
22
|
+
return {
|
|
23
|
+
'new_visual_blocking': sorted(a_vis - b_vis),
|
|
24
|
+
'removed_visual_blocking': sorted(b_vis - a_vis),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def diff_observations(
|
|
29
|
+
before: dict[str, Any],
|
|
30
|
+
after: dict[str, Any],
|
|
31
|
+
*,
|
|
32
|
+
artifacts_dir: Path | None = None,
|
|
33
|
+
scan_id_before: str = '',
|
|
34
|
+
scan_id_after: str = '',
|
|
35
|
+
) -> dict[str, Any]:
|
|
36
|
+
b_block = set(_blocking_issues(before))
|
|
37
|
+
a_block = set(_blocking_issues(after))
|
|
38
|
+
b_dom = str(before.get('dom_text') or '')
|
|
39
|
+
a_dom = str(after.get('dom_text') or '')
|
|
40
|
+
excerpt_len = 500
|
|
41
|
+
visual_delta = _visual_issues_delta(before, after)
|
|
42
|
+
|
|
43
|
+
result: dict[str, Any] = {
|
|
44
|
+
'url_before': before.get('url') or '',
|
|
45
|
+
'url_after': after.get('url') or '',
|
|
46
|
+
'url_changed': (before.get('url') or '') != (after.get('url') or ''),
|
|
47
|
+
'dom_text_changed': b_dom != a_dom,
|
|
48
|
+
'new_blocking_issues': sorted(a_block - b_block),
|
|
49
|
+
'removed_blocking_issues': sorted(b_block - a_block),
|
|
50
|
+
'dom_excerpt_before': b_dom[:excerpt_len],
|
|
51
|
+
'dom_excerpt_after': a_dom[:excerpt_len],
|
|
52
|
+
**visual_delta,
|
|
53
|
+
'visual_diff': None,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
before_shot = before.get('annotated_screenshot_path') or before.get('screenshot_path')
|
|
57
|
+
after_shot = after.get('annotated_screenshot_path') or after.get('screenshot_path')
|
|
58
|
+
if artifacts_dir and before_shot and after_shot:
|
|
59
|
+
prefix = f'{scan_id_before}_vs_{scan_id_after}'.replace('/', '_')[:80]
|
|
60
|
+
vd: VisualDiffResult = diff_screenshot_files(
|
|
61
|
+
before_shot,
|
|
62
|
+
after_shot,
|
|
63
|
+
artifacts_dir / 'diffs',
|
|
64
|
+
prefix=prefix,
|
|
65
|
+
)
|
|
66
|
+
result['visual_diff'] = vd.to_dict()
|
|
67
|
+
|
|
68
|
+
return result
|
{frontend_perception_engine-0.1.2 → frontend_perception_engine-0.2.0}/src/navigation/mcp/envelope.py
RENAMED
|
@@ -38,13 +38,22 @@ def envelope_json(**kwargs: Any) -> str:
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
def agent_summary_from_observation(obs_dict: dict[str, Any]) -> dict[str, Any]:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
"""Compact summary for host agent reasoning (no planning hints)."""
|
|
42
|
+
di = obs_dict.get('dev_insights') or {}
|
|
43
|
+
summary = di.get('summary') or {}
|
|
44
|
+
page_meta = di.get('page_meta')
|
|
45
|
+
blocking = list(summary.get('blocking_issues') or [])
|
|
46
|
+
advisory = list(summary.get('advisory_issues') or [])
|
|
47
|
+
visual = obs_dict.get('visual_insights') or {}
|
|
48
|
+
for item in visual.get('blocking') or []:
|
|
49
|
+
if item not in blocking:
|
|
50
|
+
blocking.append(item)
|
|
51
|
+
for item in visual.get('advisory') or []:
|
|
52
|
+
if item not in advisory:
|
|
53
|
+
advisory.append(item)
|
|
54
|
+
return {
|
|
55
|
+
'blocking': blocking,
|
|
56
|
+
'advisory': advisory,
|
|
57
|
+
'page_meta': page_meta,
|
|
58
|
+
'degraded': list(obs_dict.get('degraded') or []) + list(di.get('degraded') or []),
|
|
59
|
+
}
|