File size: 6,317 Bytes
0127c21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
Specialist tool registry.

Phase 4 (P0). Satisfies PS requirement: "select one or more models or
tools from a predefined registry."

This registry is deliberately just data — no model code lives here yet.
Each entry describes what a task NEEDS (image count / modality / role)
and WHICH tool would be invoked once Phases 5-8 wire in real specialist
models. The router (router.py) uses this to validate inputs and to
report a selected_tool name in the execution trace.

Do not add model inference code to this file — it's a lookup table.
"""
from __future__ import annotations

from enum import Enum
from typing import Optional, TypedDict


class TaskType(str, Enum):
    vqa = "vqa"
    captioning = "captioning"
    grounding = "grounding"
    change_detection = "change_detection"
    change_vqa = "change_vqa"
    optical_sar = "optical_sar"
    # Phase 16: follow-up chain hops 2 and 3 (uisuggestions.docx "Ask
    # Follow-up" / LEFT.md §3). NOT independently PS-mandatory — these
    # only ever get selected via agent/followup.py's followup_intent(),
    # never via agent/router.py's keyword classifier, because they only
    # make sense as a continuation of a previous grounding/change turn.
    area_estimate = "area_estimate"
    sar_cross_check = "sar_cross_check"


class TaskSpec(TypedDict):
    label: str
    ps_requirement: str
    min_images: int
    max_images: int
    allowed_roles: set[str]
    allowed_modalities: set[str]
    required_modalities: Optional[set[str]]  # if set, ALL of these must be present across inputs
    tool: str


TASK_REGISTRY: dict[TaskType, TaskSpec] = {
    TaskType.vqa: {
        "label": "Visual Question Answering",
        "ps_requirement": "Single-image VQA (mandatory baseline)",
        "min_images": 1,
        # Phase 9: up to 2 allowed (optical + SAR of the same scene) so the
        # Evidence Sufficiency Engine can pick whichever is usable — the
        # model itself still only ever looks at ONE image per call.
        "max_images": 2,
        "allowed_roles": {"single"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": None,
        "tool": "vqa_model (BLIP-VQA-base, BigEarthNet-adapted where available) — Phase 5",
    },
    TaskType.captioning: {
        "label": "Scene Captioning",
        "ps_requirement": "Additional single-image task: captioning/scene description",
        "min_images": 1,
        "max_images": 2,  # Phase 9: same optical+SAR allowance as VQA, see above
        "allowed_roles": {"single"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": None,
        "tool": "captioning_model — not yet integrated (Phase 5)",
    },
    TaskType.grounding: {
        "label": "Text-Guided Region Grounding",
        "ps_requirement": "Additional single-image task: text-guided region grounding",
        "min_images": 1,
        "max_images": 2,  # Phase 9: same optical+SAR allowance as VQA, see above
        "allowed_roles": {"single"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": None,
        "tool": "grounding_model (OWL-ViT open-vocabulary detector) — Phase 6",
    },
    TaskType.change_detection: {
        "label": "Bi-Temporal Change Detection",
        "ps_requirement": "Multi-image change analysis (mandatory): change description/change map",
        "min_images": 2,
        # Phase 12: up to 4 allowed — one optical Before/After pair PLUS
        # one SAR Before/After pair — so the Evidence Sufficiency Engine
        # can fail over to the SAR pair when the optical pair is cloudy,
        # the same way VQA/grounding already fail over to a single SAR
        # image. The model itself still only ever runs on ONE pair per
        # call (see evidence/sufficiency.py decide_temporal_evidence()).
        "max_images": 4,
        "allowed_roles": {"before", "after"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": None,
        "tool": "change_model (pixel-diff z-score change map + rule-based description) — Phase 7",
    },
    TaskType.change_vqa: {
        "label": "Change-Based Visual Question Answering",
        "ps_requirement": "Multi-image change analysis (mandatory): change-based VQA",
        "min_images": 2,
        "max_images": 4,  # Phase 12: same optical+SAR before/after allowance as above
        "allowed_roles": {"before", "after"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": None,
        "tool": "change_vqa_model (composite before|after image through BLIP-VQA + change map) — Phase 7",
    },
    TaskType.optical_sar: {
        "label": "Optical–SAR Cross-Modal Analysis",
        "ps_requirement": "Cross-modal pair analysis (mandatory): optical+SAR complementary extraction",
        "min_images": 2,
        "max_images": 2,
        "allowed_roles": {"single"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": {"optical", "sar"},
        "tool": "optical_sar_fusion_model (percentile-threshold agreement fusion) — Phase 8",
    },
    TaskType.area_estimate: {
        "label": "Follow-up: Area Estimate",
        "ps_requirement": (
            "NOT PS-mandatory — hop 2 of the follow-up chain "
            "(uisuggestions.docx 'Ask Follow-up'), only reachable via "
            "agent/followup.py after a prior grounding turn"
        ),
        "min_images": 1,
        "max_images": 2,
        "allowed_roles": {"single"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": None,
        "tool": "area_from_geotiff_gsd (pixel-box -> km\u00b2 via source GeoTIFF georeferencing) — Phase 16",
    },
    TaskType.sar_cross_check: {
        "label": "Follow-up: SAR Cross-Check",
        "ps_requirement": (
            "NOT PS-mandatory — hop 3 of the follow-up chain "
            "(uisuggestions.docx 'Ask Follow-up'), only reachable via "
            "agent/followup.py after a prior grounding turn"
        ),
        "min_images": 1,
        "max_images": 2,
        "allowed_roles": {"single"},
        "allowed_modalities": {"optical", "sar"},
        "required_modalities": {"sar"},
        "tool": "grounding_model (google/owlvit-base-patch32), re-run on the SAR image — Phase 16",
    },
}