File size: 2,067 Bytes
1397957
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Identifier generation for OpenCode API - ULID-based IDs"""

from ulid import ULID
from datetime import datetime
from typing import Literal


PrefixType = Literal["session", "message", "part", "tool", "question"]


class Identifier:
    """
    ULID-based identifier generator.
    Generates sortable, unique IDs with type prefixes.
    """
    
    PREFIXES = {
        "session": "ses",
        "message": "msg", 
        "part": "prt",
        "tool": "tol",
        "question": "qst",
    }
    
    @classmethod
    def generate(cls, prefix: PrefixType) -> str:
        """Generate a new ULID with prefix"""
        ulid = ULID()
        prefix_str = cls.PREFIXES.get(prefix, prefix[:3])
        return f"{prefix_str}_{str(ulid).lower()}"
    
    @classmethod
    def ascending(cls, prefix: PrefixType) -> str:
        """Generate an ascending (time-based) ID"""
        return cls.generate(prefix)
    
    @classmethod
    def descending(cls, prefix: PrefixType) -> str:
        """
        Generate a descending ID (for reverse chronological sorting).
        Uses inverted timestamp bits.
        """
        # For simplicity, just use regular ULID
        # In production, you'd invert the timestamp bits
        return cls.generate(prefix)
    
    @classmethod
    def parse(cls, id: str) -> tuple[str, str]:
        """Parse an ID into prefix and ULID parts"""
        parts = id.split("_", 1)
        if len(parts) != 2:
            raise ValueError(f"Invalid ID format: {id}")
        return parts[0], parts[1]
    
    @classmethod
    def validate(cls, id: str, expected_prefix: PrefixType) -> bool:
        """Validate that an ID has the expected prefix"""
        try:
            prefix, _ = cls.parse(id)
            expected = cls.PREFIXES.get(expected_prefix, expected_prefix[:3])
            return prefix == expected
        except ValueError:
            return False


# Convenience function
def generate_id(prefix: PrefixType) -> str:
    """Generate a new ULID-based ID with the given prefix."""
    return Identifier.generate(prefix)