thread-archive 0.0.2__py3-none-any.whl
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.
- thread_archive/__init__.py +34 -0
- thread_archive/_api.py +2235 -0
- thread_archive/_config.py +126 -0
- thread_archive/_importers/__init__.py +81 -0
- thread_archive/_importers/_continuation.py +136 -0
- thread_archive/_importers/_cursor.py +103 -0
- thread_archive/_importers/_events.py +244 -0
- thread_archive/_importers/_line_stream.py +193 -0
- thread_archive/_importers/_read.py +82 -0
- thread_archive/_importers/_result.py +17 -0
- thread_archive/_importers/_sidecar.py +113 -0
- thread_archive/_importers/_state.py +240 -0
- thread_archive/_importers/_titles.py +179 -0
- thread_archive/_importers/antigravity.py +254 -0
- thread_archive/_importers/claude_code.py +293 -0
- thread_archive/_importers/claude_science.py +330 -0
- thread_archive/_importers/cloth.py +20 -0
- thread_archive/_importers/codex.py +324 -0
- thread_archive/_importers/cowork.py +107 -0
- thread_archive/_importers/cursor.py +432 -0
- thread_archive/_importers/exports.py +389 -0
- thread_archive/_importers/grok.py +600 -0
- thread_archive/_importers/opencode.py +538 -0
- thread_archive/_knowledge/__init__.py +67 -0
- thread_archive/_knowledge/_claims.py +116 -0
- thread_archive/_knowledge/_community.py +75 -0
- thread_archive/_knowledge/graph.py +208 -0
- thread_archive/_knowledge/materialize.py +212 -0
- thread_archive/_knowledge/write.py +438 -0
- thread_archive/_launchd.py +167 -0
- thread_archive/_mcp/__init__.py +1 -0
- thread_archive/_mcp/librarian.py +151 -0
- thread_archive/_mcp/server.py +307 -0
- thread_archive/_retrieval/__init__.py +280 -0
- thread_archive/_retrieval/_classify.py +80 -0
- thread_archive/_retrieval/_codex.py +157 -0
- thread_archive/_retrieval/_context.py +123 -0
- thread_archive/_retrieval/_extract.py +184 -0
- thread_archive/_retrieval/embed.py +186 -0
- thread_archive/_retrieval/format.py +149 -0
- thread_archive/_retrieval/fts.py +538 -0
- thread_archive/_retrieval/rank.py +228 -0
- thread_archive/_retrieval/read.py +908 -0
- thread_archive/_retrieval/rerank.py +143 -0
- thread_archive/_retrieval/vectors.py +611 -0
- thread_archive/_scripts/__init__.py +1 -0
- thread_archive/_scripts/backfill_recompute.py +328 -0
- thread_archive/_scripts/backfill_reconcile.py +296 -0
- thread_archive/_scripts/denamespace_dedup_keys.py +120 -0
- thread_archive/_scripts/recover_dropped_events.py +190 -0
- thread_archive/_scripts/repair_grok_tool_names.py +118 -0
- thread_archive/_scripts/repair_grok_tool_names_backup_20260704T155625Z.json +275 -0
- thread_archive/_scripts/repair_grok_tool_names_plan_20260704.json +435 -0
- thread_archive/_setup/__init__.py +12 -0
- thread_archive/_setup/clients.py +89 -0
- thread_archive/_setup/wizard.py +474 -0
- thread_archive/_store/__init__.py +45 -0
- thread_archive/_store/_base.py +173 -0
- thread_archive/_store/_defaults.py +57 -0
- thread_archive/_store/_types.py +38 -0
- thread_archive/_store/models.py +370 -0
- thread_archive/_store/schema.py +84 -0
- thread_archive/_thread_import/__init__.py +40 -0
- thread_archive/_thread_import/api.py +78 -0
- thread_archive/_thread_import/event_builder.py +810 -0
- thread_archive/_thread_import/exporters/__init__.py +9 -0
- thread_archive/_thread_import/exporters/_cursor_kv_mixin.py +166 -0
- thread_archive/_thread_import/exporters/_cursor_parse_mixin.py +149 -0
- thread_archive/_thread_import/exporters/cursor.py +582 -0
- thread_archive/_thread_import/exporters/cursor_parse.py +145 -0
- thread_archive/_thread_import/parsers/__init__.py +191 -0
- thread_archive/_thread_import/parsers/base.py +698 -0
- thread_archive/_thread_import/parsers/chatgpt.py +722 -0
- thread_archive/_thread_import/parsers/chatgpt_content.py +332 -0
- thread_archive/_thread_import/parsers/claude.py +443 -0
- thread_archive/_thread_import/parsers/claude_code.py +1035 -0
- thread_archive/_thread_import/parsers/claude_code_blocks.py +415 -0
- thread_archive/_thread_import/parsers/claude_code_ide.py +122 -0
- thread_archive/_thread_import/parsers/claude_code_sessions.py +90 -0
- thread_archive/_thread_import/parsers/config/__init__.py +26 -0
- thread_archive/_thread_import/parsers/config/base.py +220 -0
- thread_archive/_thread_import/parsers/cursor.py +538 -0
- thread_archive/_thread_import/parsers/cursor_blocks.py +365 -0
- thread_archive/_thread_import/parsers/pipeline/__init__.py +29 -0
- thread_archive/_thread_import/parsers/pipeline/base.py +251 -0
- thread_archive/_thread_import/parsers/pipeline/interfaces.py +191 -0
- thread_archive/_thread_import/parsers/transformers/__init__.py +22 -0
- thread_archive/_thread_import/parsers/transformers/active_path.py +87 -0
- thread_archive/_thread_import/parsers/transformers/coalescing.py +389 -0
- thread_archive/_thread_import/parsers/transformers/ide_context.py +158 -0
- thread_archive/_thread_import/parsers/transformers/thinking_merge.py +68 -0
- thread_archive/_thread_import/parsers/types/__init__.py +56 -0
- thread_archive/_thread_import/parsers/types/chatgpt.py +99 -0
- thread_archive/_thread_import/parsers/types/claude.py +120 -0
- thread_archive/_thread_import/parsers/types/claude_code.py +139 -0
- thread_archive/_thread_import/parsers/types/cursor.py +109 -0
- thread_archive/_thread_import/parsers/validators/__init__.py +83 -0
- thread_archive/_thread_import/parsers/validators/base.py +168 -0
- thread_archive/_thread_import/parsers/validators/content.py +80 -0
- thread_archive/_thread_import/parsers/validators/referential.py +57 -0
- thread_archive/_thread_import/parsers/validators/thinking.py +143 -0
- thread_archive/_thread_import/parsers/validators/types.py +87 -0
- thread_archive/_thread_import/schemas/__init__.py +231 -0
- thread_archive/_thread_import/schemas/chatgpt/v1.json +197 -0
- thread_archive/_thread_import/schemas/chatgpt/v2.json +203 -0
- thread_archive/_thread_import/schemas/claude/v1.json +188 -0
- thread_archive/_thread_import/schemas/claude_code/v1.json +183 -0
- thread_archive/_thread_import/schemas/cursor/v1.json +143 -0
- thread_archive/_thread_import/schemas/cursor/v2.json +200 -0
- thread_archive/_thread_import/timestamps.py +57 -0
- thread_archive/_thread_import/tool_names.py +48 -0
- thread_archive/_truth/__init__.py +40 -0
- thread_archive/_truth/jsonl_log.py +2340 -0
- thread_archive/_truth/repair.py +322 -0
- thread_archive/_watcher/__init__.py +57 -0
- thread_archive/_watcher/base.py +65 -0
- thread_archive/_watcher/daemon.py +289 -0
- thread_archive/_watcher/export_drop.py +203 -0
- thread_archive/_watcher/exthost.py +316 -0
- thread_archive/_watcher/lazy.py +117 -0
- thread_archive/_watcher/sources.py +616 -0
- thread_archive/_web/__init__.py +15 -0
- thread_archive/_web/server.py +299 -0
- thread_archive/_web/static/assets/index-DECSH1Mz.css +10 -0
- thread_archive/_web/static/assets/index-Djq0FK0y.js +101 -0
- thread_archive/_web/static/index.html +13 -0
- thread_archive/cli.py +746 -0
- thread_archive-0.0.2.dist-info/METADATA +296 -0
- thread_archive-0.0.2.dist-info/RECORD +132 -0
- thread_archive-0.0.2.dist-info/WHEEL +4 -0
- thread_archive-0.0.2.dist-info/entry_points.txt +6 -0
- thread_archive-0.0.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provider configuration dataclasses.
|
|
3
|
+
|
|
4
|
+
ProviderConfig captures provider-specific characteristics that affect
|
|
5
|
+
parsing and validation. This moves configuration out of base.py and
|
|
6
|
+
makes it owned by each provider.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Dict, Literal, Optional, Set
|
|
11
|
+
|
|
12
|
+
# Type alias for thinking block expectations
|
|
13
|
+
ThinkingExpectation = Literal["never", "required", "model_specific", "optional"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class ProviderConfig:
|
|
18
|
+
"""Provider-specific parsing and validation configuration.
|
|
19
|
+
|
|
20
|
+
Each parser has a PROVIDER_CONFIG class attribute that configures
|
|
21
|
+
validation behavior, expected roles/block types, and model-specific
|
|
22
|
+
thinking requirements.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
provider_name: Unique identifier for the provider
|
|
26
|
+
thinking_expectation: How to validate thinking blocks
|
|
27
|
+
- "never": Error if thinking blocks exist (wrong parser/source)
|
|
28
|
+
- "required": Error if no thinking blocks (incomplete export)
|
|
29
|
+
- "model_specific": Validate per-message based on model field
|
|
30
|
+
- "optional": No validation
|
|
31
|
+
thinking_exempt_models: Models that don't require thinking blocks
|
|
32
|
+
(only used when thinking_expectation="model_specific")
|
|
33
|
+
has_branching: Whether conversations can have branches/alternate paths
|
|
34
|
+
has_parent_references: Whether messages have parent references
|
|
35
|
+
expected_roles: Valid role values for this provider
|
|
36
|
+
expected_block_types: Valid content block types for this provider
|
|
37
|
+
timestamp_format: How timestamps are formatted in exports
|
|
38
|
+
- "unix_seconds": Unix timestamp in seconds
|
|
39
|
+
- "unix_millis": Unix timestamp in milliseconds
|
|
40
|
+
- "iso": ISO 8601 string
|
|
41
|
+
- "mixed": Can be any of the above (auto-detect)
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
provider_name: str
|
|
45
|
+
thinking_expectation: ThinkingExpectation = "optional"
|
|
46
|
+
thinking_exempt_models: Set[str] = field(default_factory=set)
|
|
47
|
+
has_branching: bool = False
|
|
48
|
+
has_parent_references: bool = False
|
|
49
|
+
expected_roles: Set[str] = field(
|
|
50
|
+
default_factory=lambda: {"user", "assistant", "system"}
|
|
51
|
+
)
|
|
52
|
+
expected_block_types: Set[str] = field(default_factory=set)
|
|
53
|
+
timestamp_format: Literal["unix_seconds", "unix_millis", "iso", "mixed"] = "mixed"
|
|
54
|
+
|
|
55
|
+
def requires_thinking(self, model: Optional[str]) -> bool:
|
|
56
|
+
"""Check if a specific model requires thinking blocks.
|
|
57
|
+
|
|
58
|
+
Default behavior: unknown models REQUIRE thinking (safer - catches missing data).
|
|
59
|
+
Only whitelisted non-reasoning models are exempt.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
model: Model name/slug from the message
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
True if thinking blocks are required for this model
|
|
66
|
+
"""
|
|
67
|
+
if self.thinking_expectation != "model_specific":
|
|
68
|
+
return self.thinking_expectation == "required"
|
|
69
|
+
|
|
70
|
+
if not model:
|
|
71
|
+
return True # Unknown model = require thinking
|
|
72
|
+
|
|
73
|
+
model_lower = model.lower()
|
|
74
|
+
|
|
75
|
+
# Check if model is in the exempt list
|
|
76
|
+
for exempt_model in self.thinking_exempt_models:
|
|
77
|
+
exempt_lower = exempt_model.lower()
|
|
78
|
+
if model_lower == exempt_lower or model_lower.startswith(f"{exempt_lower}-"):
|
|
79
|
+
return False # Known non-reasoning model
|
|
80
|
+
|
|
81
|
+
return True # Default: require thinking
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# =============================================================================
|
|
85
|
+
# Provider-specific configurations
|
|
86
|
+
# =============================================================================
|
|
87
|
+
|
|
88
|
+
# Common non-reasoning models shared across providers
|
|
89
|
+
_COMMON_EXEMPT_MODELS = {
|
|
90
|
+
# OpenAI non-reasoning models
|
|
91
|
+
"gpt-4",
|
|
92
|
+
"gpt-4-turbo",
|
|
93
|
+
"gpt-4o",
|
|
94
|
+
"gpt-4o-mini",
|
|
95
|
+
"gpt-3.5-turbo",
|
|
96
|
+
"gpt-3.5",
|
|
97
|
+
"chatgpt-4o-latest",
|
|
98
|
+
# Anthropic non-thinking models (note: Opus 4.5 DOES have thinking)
|
|
99
|
+
"claude-3-5-sonnet",
|
|
100
|
+
"claude-sonnet-4-5",
|
|
101
|
+
"claude-3-5-sonnet-20241022",
|
|
102
|
+
"claude-3-5-haiku",
|
|
103
|
+
"claude-haiku-3-5",
|
|
104
|
+
"claude-3-opus",
|
|
105
|
+
"claude-3-sonnet",
|
|
106
|
+
"claude-3-haiku",
|
|
107
|
+
"claude-2",
|
|
108
|
+
"claude-2.1",
|
|
109
|
+
"claude-instant",
|
|
110
|
+
"claude-sonnet-4-5-20250929",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
CHATGPT_CONFIG = ProviderConfig(
|
|
115
|
+
provider_name="chatgpt",
|
|
116
|
+
thinking_expectation="model_specific",
|
|
117
|
+
thinking_exempt_models=_COMMON_EXEMPT_MODELS,
|
|
118
|
+
has_branching=True,
|
|
119
|
+
has_parent_references=True,
|
|
120
|
+
expected_roles={"user", "assistant", "system", "tool"},
|
|
121
|
+
expected_block_types={
|
|
122
|
+
"text",
|
|
123
|
+
"thinking",
|
|
124
|
+
"tool_use",
|
|
125
|
+
"tool_result",
|
|
126
|
+
"image",
|
|
127
|
+
"system_context",
|
|
128
|
+
},
|
|
129
|
+
timestamp_format="unix_seconds",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
CLAUDE_CONFIG = ProviderConfig(
|
|
134
|
+
provider_name="claude",
|
|
135
|
+
# Claude.ai web exports NEVER include thinking blocks (server-side only)
|
|
136
|
+
thinking_expectation="never",
|
|
137
|
+
thinking_exempt_models=set(), # Not applicable - expectation is "never"
|
|
138
|
+
has_branching=False,
|
|
139
|
+
has_parent_references=False,
|
|
140
|
+
expected_roles={"user", "assistant", "human"}, # Claude uses "human" for user
|
|
141
|
+
expected_block_types={
|
|
142
|
+
"text",
|
|
143
|
+
"tool_use",
|
|
144
|
+
"tool_result",
|
|
145
|
+
"system_metadata",
|
|
146
|
+
},
|
|
147
|
+
timestamp_format="iso",
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
CLAUDE_CODE_CONFIG = ProviderConfig(
|
|
152
|
+
provider_name="claude-code",
|
|
153
|
+
thinking_expectation="model_specific",
|
|
154
|
+
thinking_exempt_models=_COMMON_EXEMPT_MODELS,
|
|
155
|
+
has_branching=True, # Tree via uuid/parentUuid
|
|
156
|
+
has_parent_references=True,
|
|
157
|
+
expected_roles={"user", "assistant", "system"},
|
|
158
|
+
expected_block_types={
|
|
159
|
+
"text",
|
|
160
|
+
"thinking",
|
|
161
|
+
"tool_use",
|
|
162
|
+
"tool_result",
|
|
163
|
+
"ide_context",
|
|
164
|
+
"file_snapshot",
|
|
165
|
+
"context_summary",
|
|
166
|
+
"system_context",
|
|
167
|
+
"parse_error",
|
|
168
|
+
"image", # pasted screenshots/images in a Claude Code session
|
|
169
|
+
"queue_operation", # Claude Code's message-queue feature (queued while the agent works)
|
|
170
|
+
"progress", # hook/tool progress telemetry (e.g. PostToolUse hook callbacks)
|
|
171
|
+
},
|
|
172
|
+
timestamp_format="iso",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
CURSOR_CONFIG = ProviderConfig(
|
|
177
|
+
provider_name="cursor",
|
|
178
|
+
thinking_expectation="model_specific",
|
|
179
|
+
thinking_exempt_models=_COMMON_EXEMPT_MODELS,
|
|
180
|
+
has_branching=False,
|
|
181
|
+
has_parent_references=False,
|
|
182
|
+
expected_roles={"user", "assistant", "system", "tool"},
|
|
183
|
+
expected_block_types={
|
|
184
|
+
"text",
|
|
185
|
+
"thinking",
|
|
186
|
+
"tool_use",
|
|
187
|
+
"tool_result",
|
|
188
|
+
"code",
|
|
189
|
+
},
|
|
190
|
+
timestamp_format="mixed", # Can be ISO string or Unix timestamp
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# Registry of all provider configs
|
|
195
|
+
_PROVIDER_CONFIGS: Dict[str, ProviderConfig] = {
|
|
196
|
+
"chatgpt": CHATGPT_CONFIG,
|
|
197
|
+
"claude": CLAUDE_CONFIG,
|
|
198
|
+
"claude-code": CLAUDE_CODE_CONFIG,
|
|
199
|
+
"cursor": CURSOR_CONFIG,
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def get_provider_config(provider: str) -> ProviderConfig:
|
|
204
|
+
"""Get the configuration for a provider.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
provider: Provider name (chatgpt, claude, claude-code, cursor)
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
ProviderConfig for the provider
|
|
211
|
+
|
|
212
|
+
Raises:
|
|
213
|
+
KeyError: If provider is not known
|
|
214
|
+
"""
|
|
215
|
+
if provider not in _PROVIDER_CONFIGS:
|
|
216
|
+
raise KeyError(
|
|
217
|
+
f"Unknown provider: {provider}. "
|
|
218
|
+
f"Known providers: {list(_PROVIDER_CONFIGS.keys())}"
|
|
219
|
+
)
|
|
220
|
+
return _PROVIDER_CONFIGS[provider]
|