Spaces:
Sleeping
Sleeping
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)
|