Pattern-011: Context Resolution Pattern

Status

Proven

Context

Applications often need to resolve implicit context (like current project, user session, or workspace) from multiple potential sources with conflicting information. Without clear precedence rules, context resolution becomes unpredictable and error-prone. The Context Resolution Pattern addresses:

Pattern Description

The Context Resolution Pattern resolves implicit context from multiple sources using clear precedence rules, ensuring predictable and consistent context determination across the application.

Core concept:

Implementation

Structure

class ProjectContext:
    """Resolves project from various sources"""

    def __init__(self, repository: ProjectRepository, llm: LLMClient):
        self.repo = repository
        self.llm = llm
        self._session_memory: Dict[str, str] = {}

    async def resolve_project(
        self,
        intent: Intent,
        session_id: str,
        confirmed: bool = False
    ) -> Tuple[Project, bool]:
        """
        Resolution hierarchy:
        1. Explicit project_id (always wins)
        2. Session history (if confirmed)
        3. LLM inference from message
        4. Default project fallback
        """

        # 1. Explicit always wins
        if project_id := intent.context.get("project_id"):
            project = await self.repo.get_by_id(project_id)
            if not project:
                raise ProjectNotFoundError(project_id)
            return project, False

        # 2. Session history
        if session_id in self._session_memory and confirmed:
            project = await self.repo.get_by_id(self._session_memory[session_id])
            return project, False

        # 3. Inference
        inferred = await self._infer_from_message(intent)
        if inferred:
            self._session_memory[session_id] = inferred.id
            needs_confirm = session_id in self._session_memory and \
                           self._session_memory[session_id] != inferred.id
            return inferred, needs_confirm

        # 4. Default fallback
        default = await self.repo.get_default_project()
        if default:
            return default, True

        raise NoProjectAvailableError("No project context available")

    async def _infer_from_message(self, intent: Intent) -> Optional[Project]:
        """Use LLM to infer project from message content"""
        projects = await self.repo.list_active_projects()
        if not projects:
            return None

        project_context = "\n".join([f"- {p.name}: {p.description}" for p in projects])

        prompt = f"""
        Given this message: "{intent.message}"
        And these available projects:
        {project_context}

        Which project is this message most likely referring to? Return just the project name or 'none'.
        """

        response = await self.llm.complete(prompt)
        for project in projects:
            if project.name.lower() in response.lower():
                return project

        return None

Generic Context Resolver

class ContextResolver[T]:
    """Generic context resolution pattern"""

    def __init__(self, sources: List[ContextSource[T]]):
        self.sources = sorted(sources, key=lambda s: s.priority, reverse=True)

    async def resolve(self, context_data: Dict[str, Any]) -> T:
        """Resolve context using source priority hierarchy"""
        for source in self.sources:
            try:
                result = await source.resolve(context_data)
                if result:
                    return result
            except ContextResolutionError:
                continue  # Try next source

        raise ContextNotResolvableError("No source could resolve context")

class ExplicitContextSource(ContextSource[Project]):
    """Highest priority - explicit specification"""
    priority = 100

    async def resolve(self, context_data: Dict[str, Any]) -> Optional[Project]:
        project_id = context_data.get("project_id")
        if project_id:
            return await self.repository.get_by_id(project_id)
        return None

class SessionContextSource(ContextSource[Project]):
    """Medium priority - session memory"""
    priority = 50

    async def resolve(self, context_data: Dict[str, Any]) -> Optional[Project]:
        session_id = context_data.get("session_id")
        if session_id and context_data.get("confirmed"):
            return await self.get_session_project(session_id)
        return None

Usage Guidelines

Resolution Hierarchy Design

Session Management

Error Handling

Benefits

Trade-offs

Anti-patterns to Avoid

References

Migration Notes

Consolidated from: