indent 0.0.8__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.
Potentially problematic release.
This version of indent might be problematic. Click here for more details.
- exponent/__init__.py +1 -0
- exponent/cli.py +112 -0
- exponent/commands/cloud_commands.py +85 -0
- exponent/commands/common.py +434 -0
- exponent/commands/config_commands.py +581 -0
- exponent/commands/github_app_commands.py +211 -0
- exponent/commands/listen_commands.py +96 -0
- exponent/commands/run_commands.py +208 -0
- exponent/commands/settings.py +56 -0
- exponent/commands/shell_commands.py +2840 -0
- exponent/commands/theme.py +246 -0
- exponent/commands/types.py +111 -0
- exponent/commands/upgrade.py +29 -0
- exponent/commands/utils.py +236 -0
- exponent/core/config.py +180 -0
- exponent/core/graphql/__init__.py +0 -0
- exponent/core/graphql/client.py +59 -0
- exponent/core/graphql/cloud_config_queries.py +77 -0
- exponent/core/graphql/get_chats_query.py +47 -0
- exponent/core/graphql/github_config_queries.py +56 -0
- exponent/core/graphql/mutations.py +75 -0
- exponent/core/graphql/queries.py +110 -0
- exponent/core/graphql/subscriptions.py +452 -0
- exponent/core/remote_execution/checkpoints.py +212 -0
- exponent/core/remote_execution/cli_rpc_types.py +214 -0
- exponent/core/remote_execution/client.py +545 -0
- exponent/core/remote_execution/code_execution.py +58 -0
- exponent/core/remote_execution/command_execution.py +105 -0
- exponent/core/remote_execution/error_info.py +45 -0
- exponent/core/remote_execution/exceptions.py +10 -0
- exponent/core/remote_execution/file_write.py +410 -0
- exponent/core/remote_execution/files.py +415 -0
- exponent/core/remote_execution/git.py +268 -0
- exponent/core/remote_execution/languages/python_execution.py +239 -0
- exponent/core/remote_execution/languages/shell_streaming.py +221 -0
- exponent/core/remote_execution/languages/types.py +20 -0
- exponent/core/remote_execution/session.py +128 -0
- exponent/core/remote_execution/system_context.py +54 -0
- exponent/core/remote_execution/tool_execution.py +289 -0
- exponent/core/remote_execution/truncation.py +284 -0
- exponent/core/remote_execution/types.py +670 -0
- exponent/core/remote_execution/utils.py +600 -0
- exponent/core/types/__init__.py +0 -0
- exponent/core/types/command_data.py +206 -0
- exponent/core/types/event_types.py +89 -0
- exponent/core/types/generated/__init__.py +0 -0
- exponent/core/types/generated/strategy_info.py +225 -0
- exponent/migration-docs/login.md +112 -0
- exponent/py.typed +4 -0
- exponent/utils/__init__.py +0 -0
- exponent/utils/colors.py +92 -0
- exponent/utils/version.py +289 -0
- indent-0.0.8.dist-info/METADATA +36 -0
- indent-0.0.8.dist-info/RECORD +56 -0
- indent-0.0.8.dist-info/WHEEL +4 -0
- indent-0.0.8.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Annotated, Any, ClassVar, Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
WRITE_STRATEGY_FULL_FILE_REWRITE: Literal["FULL_FILE_REWRITE"] = "FULL_FILE_REWRITE"
|
|
8
|
+
DEFAULT_CODE_BLOCK_TIMEOUT = 30
|
|
9
|
+
WRITE_STRATEGY_NATURAL_EDIT: Literal["NATURAL_EDIT"] = "NATURAL_EDIT"
|
|
10
|
+
WRITE_STRATEGY_SEARCH_REPLACE: Literal["SEARCH_REPLACE"] = "SEARCH_REPLACE"
|
|
11
|
+
WRITE_STRATEGY_UDIFF: Literal["UDIFF"] = "UDIFF"
|
|
12
|
+
|
|
13
|
+
FileWriteStrategyName = Literal[
|
|
14
|
+
"FULL_FILE_REWRITE", "UDIFF", "SEARCH_REPLACE", "NATURAL_EDIT"
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CommandType(str, Enum):
|
|
19
|
+
THINKING = "thinking"
|
|
20
|
+
FILE_READ = "file_read"
|
|
21
|
+
SUMMARIZE = "summarize"
|
|
22
|
+
STEP_OUTPUT = "step_output"
|
|
23
|
+
PROTOTYPE = "prototype"
|
|
24
|
+
DB_QUERY = "db_query"
|
|
25
|
+
DB_GET_TABLE_NAMES = "db_get_table_names"
|
|
26
|
+
DB_GET_TABLE_SCHEMA = "db_get_table_schema"
|
|
27
|
+
ANSWER = "answer"
|
|
28
|
+
ASK = "ask"
|
|
29
|
+
SHELL = "shell"
|
|
30
|
+
PYTHON = "python"
|
|
31
|
+
FILE_WRITE = "file_write"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CommandData(BaseModel):
|
|
35
|
+
executable: ClassVar[bool]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FileReadCommandData(CommandData):
|
|
39
|
+
executable: ClassVar[bool] = True
|
|
40
|
+
type: Literal[CommandType.FILE_READ] = CommandType.FILE_READ
|
|
41
|
+
|
|
42
|
+
file_path: str
|
|
43
|
+
language: str
|
|
44
|
+
limit: int | None = None
|
|
45
|
+
offset: int | None = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ThinkingCommandData(CommandData):
|
|
49
|
+
executable: ClassVar[bool] = False
|
|
50
|
+
type: Literal[CommandType.THINKING] = CommandType.THINKING
|
|
51
|
+
|
|
52
|
+
content: str
|
|
53
|
+
signature: str | None = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class PrototypeCommandData(CommandData):
|
|
57
|
+
executable: ClassVar[bool] = True
|
|
58
|
+
type: Literal[CommandType.PROTOTYPE] = CommandType.PROTOTYPE
|
|
59
|
+
|
|
60
|
+
command_name: str
|
|
61
|
+
# Structured data extracted from LLM output
|
|
62
|
+
content_json: dict[str, Any]
|
|
63
|
+
# Raw text extracted from LLM output
|
|
64
|
+
content_raw: str
|
|
65
|
+
# Rendered LLM output for frontend display
|
|
66
|
+
content_rendered: str
|
|
67
|
+
|
|
68
|
+
llm_command_name_override: str | None = None
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def llm_command_name(self) -> str:
|
|
72
|
+
return self.llm_command_name_override or self.command_name
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# deprecated, use StepOutputCommandData instead
|
|
76
|
+
class SummarizeCommandData(CommandData):
|
|
77
|
+
executable: ClassVar[bool] = True
|
|
78
|
+
type: Literal[CommandType.SUMMARIZE] = CommandType.SUMMARIZE
|
|
79
|
+
|
|
80
|
+
summary: str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class StepOutputCommandData(CommandData):
|
|
84
|
+
executable: ClassVar[bool] = True
|
|
85
|
+
type: Literal[CommandType.STEP_OUTPUT] = CommandType.STEP_OUTPUT
|
|
86
|
+
|
|
87
|
+
step_output_raw: str
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class DBQueryCommandData(CommandData):
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
**kwargs: Any,
|
|
94
|
+
) -> None:
|
|
95
|
+
super().__init__(**kwargs)
|
|
96
|
+
|
|
97
|
+
executable: ClassVar[bool] = True
|
|
98
|
+
type: Literal[CommandType.DB_QUERY] = CommandType.DB_QUERY
|
|
99
|
+
|
|
100
|
+
query: str
|
|
101
|
+
max_gigabytes_billed: float | None = None # BigQuery only
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class DBGetTableNamesCommandData(CommandData):
|
|
105
|
+
executable: ClassVar[bool] = True
|
|
106
|
+
type: Literal[CommandType.DB_GET_TABLE_NAMES] = CommandType.DB_GET_TABLE_NAMES
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class DBGetTableSchemaCommandData(CommandData):
|
|
110
|
+
executable: ClassVar[bool] = True
|
|
111
|
+
type: Literal[CommandType.DB_GET_TABLE_SCHEMA] = CommandType.DB_GET_TABLE_SCHEMA
|
|
112
|
+
|
|
113
|
+
table_name: str
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class AnswerCommandData(CommandData):
|
|
117
|
+
executable: ClassVar[bool] = False
|
|
118
|
+
type: Literal[CommandType.ANSWER] = CommandType.ANSWER
|
|
119
|
+
|
|
120
|
+
answer_raw: str
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class AskCommandData(CommandData):
|
|
124
|
+
executable: ClassVar[bool] = False
|
|
125
|
+
type: Literal[CommandType.ASK] = CommandType.ASK
|
|
126
|
+
|
|
127
|
+
ask_raw: str
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class ShellCommandData(CommandData):
|
|
131
|
+
exclude_from_schema_gen: ClassVar[bool] = True
|
|
132
|
+
|
|
133
|
+
executable: ClassVar[bool] = True
|
|
134
|
+
type: Literal[CommandType.SHELL] = CommandType.SHELL
|
|
135
|
+
|
|
136
|
+
timeout: int = DEFAULT_CODE_BLOCK_TIMEOUT
|
|
137
|
+
content: str
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class PythonCommandData(CommandData):
|
|
141
|
+
exclude_from_schema_gen: ClassVar[bool] = True
|
|
142
|
+
|
|
143
|
+
executable: ClassVar[bool] = True
|
|
144
|
+
type: Literal[CommandType.PYTHON] = CommandType.PYTHON
|
|
145
|
+
|
|
146
|
+
content: str
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class EditContent(BaseModel):
|
|
150
|
+
content: str
|
|
151
|
+
original_file: str | None = None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class NaturalEditContent(BaseModel):
|
|
155
|
+
natural_edit: str
|
|
156
|
+
intermediate_edit: str | None
|
|
157
|
+
original_file: str | None
|
|
158
|
+
new_file: str | None
|
|
159
|
+
error_content: str | None
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def is_resolved(self) -> bool:
|
|
163
|
+
return self.new_file is not None or self.error_content is not None
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def is_noop(self) -> bool:
|
|
167
|
+
return bool(
|
|
168
|
+
self.new_file is not None
|
|
169
|
+
and self.original_file is not None
|
|
170
|
+
and self.new_file == self.original_file
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class FileWriteCommandData(CommandData):
|
|
175
|
+
exclude_from_schema_gen: ClassVar[bool] = True
|
|
176
|
+
|
|
177
|
+
executable: ClassVar[bool] = True
|
|
178
|
+
type: Literal[CommandType.FILE_WRITE] = CommandType.FILE_WRITE
|
|
179
|
+
|
|
180
|
+
file_path: str
|
|
181
|
+
language: str
|
|
182
|
+
write_strategy: FileWriteStrategyName
|
|
183
|
+
write_content: NaturalEditContent | EditContent
|
|
184
|
+
content: str
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
CommandDataType = Annotated[
|
|
188
|
+
FileReadCommandData
|
|
189
|
+
| ThinkingCommandData
|
|
190
|
+
| PrototypeCommandData
|
|
191
|
+
| SummarizeCommandData
|
|
192
|
+
| DBQueryCommandData
|
|
193
|
+
| DBGetTableNamesCommandData
|
|
194
|
+
| DBGetTableSchemaCommandData
|
|
195
|
+
| StepOutputCommandData
|
|
196
|
+
| AnswerCommandData
|
|
197
|
+
| AskCommandData
|
|
198
|
+
| ShellCommandData
|
|
199
|
+
| PythonCommandData
|
|
200
|
+
| FileWriteCommandData,
|
|
201
|
+
Field(discriminator="type"),
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class CommandImpl(ABC):
|
|
206
|
+
command_data_type: ClassVar[type[CommandData]]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Generic, Protocol, TypeVar, Union
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field, JsonValue, ValidationInfo, field_validator
|
|
6
|
+
|
|
7
|
+
from exponent.core.types.command_data import (
|
|
8
|
+
DEFAULT_CODE_BLOCK_TIMEOUT,
|
|
9
|
+
WRITE_STRATEGY_NATURAL_EDIT,
|
|
10
|
+
CommandDataType,
|
|
11
|
+
EditContent,
|
|
12
|
+
FileWriteStrategyName,
|
|
13
|
+
NaturalEditContent,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FileWriteErrorType(str, Enum):
|
|
18
|
+
TERMINATION_REQUESTED = "TERMINATION_REQUESTED"
|
|
19
|
+
NO_OP = "NO_OP"
|
|
20
|
+
FAILED_APPLY = "FAILED_APPLY"
|
|
21
|
+
FAILED_GENERATION = "FAILED_GENERATION"
|
|
22
|
+
CLI_DISCONNECTED = "CLI_DISCONNECTED"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ExponentEvent(BaseModel):
|
|
26
|
+
chat_uuid: str
|
|
27
|
+
event_uuid: str
|
|
28
|
+
parent_uuid: str | None
|
|
29
|
+
turn_uuid: str
|
|
30
|
+
|
|
31
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PersistedExponentEvent(ExponentEvent):
|
|
35
|
+
db_timestamp: datetime | None = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CodeBlockEvent(PersistedExponentEvent):
|
|
39
|
+
language: str
|
|
40
|
+
content: str
|
|
41
|
+
timeout: int = DEFAULT_CODE_BLOCK_TIMEOUT
|
|
42
|
+
require_confirmation: bool = False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class FileWriteEvent(PersistedExponentEvent):
|
|
46
|
+
file_path: str
|
|
47
|
+
language: str
|
|
48
|
+
write_strategy: FileWriteStrategyName
|
|
49
|
+
write_content: NaturalEditContent | EditContent
|
|
50
|
+
content: str
|
|
51
|
+
error_content: str | None
|
|
52
|
+
error_type: FileWriteErrorType | None
|
|
53
|
+
require_confirmation: bool = False
|
|
54
|
+
|
|
55
|
+
@field_validator("write_content")
|
|
56
|
+
def validate_write_content_type(
|
|
57
|
+
cls, v: NaturalEditContent | EditContent, info: ValidationInfo
|
|
58
|
+
) -> NaturalEditContent | EditContent:
|
|
59
|
+
write_strategy = info.data.get("write_strategy")
|
|
60
|
+
if write_strategy == WRITE_STRATEGY_NATURAL_EDIT:
|
|
61
|
+
if not isinstance(v, NaturalEditContent):
|
|
62
|
+
raise ValueError(
|
|
63
|
+
"When write_strategy is NATURAL_EDIT, write_content must be NaturalEditContent"
|
|
64
|
+
)
|
|
65
|
+
elif not isinstance(v, EditContent):
|
|
66
|
+
raise ValueError(
|
|
67
|
+
"For non-NATURAL_EDIT strategies, write_content must be EditContent"
|
|
68
|
+
)
|
|
69
|
+
return v
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
T = TypeVar("T", bound=CommandDataType)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class HoldsCommandData(Protocol, Generic[T]):
|
|
76
|
+
data: T
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class CommandEvent(PersistedExponentEvent):
|
|
80
|
+
data: CommandDataType
|
|
81
|
+
require_confirmation: bool = False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class MultiCommandEvent(PersistedExponentEvent):
|
|
85
|
+
data: list[CommandDataType]
|
|
86
|
+
require_confirmation: bool = False
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
LocalEventType = Union[FileWriteEvent, CodeBlockEvent, CommandEvent]
|
|
File without changes
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Auto-generated, do not edit directly. Run `make generate_strategy_info` to update.
|
|
2
|
+
|
|
3
|
+
import enum
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from exponent.core.remote_execution.types import ChatMode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class StrategyName(str, enum.Enum):
|
|
11
|
+
NATURAL_EDIT_CLAUDE_3_7_XML = "NATURAL_EDIT_CLAUDE_3_7_XML"
|
|
12
|
+
READ_ONLY = "READ_ONLY"
|
|
13
|
+
NATURAL_EDIT_CLAUDE_3_7_XML_WITH_STEPS = "NATURAL_EDIT_CLAUDE_3_7_XML_WITH_STEPS"
|
|
14
|
+
NATURAL_EDIT_CLAUDE_3_7_FUNCTION_CALLING = (
|
|
15
|
+
"NATURAL_EDIT_CLAUDE_3_7_FUNCTION_CALLING"
|
|
16
|
+
)
|
|
17
|
+
SEARCH_REPLACE_FUNCTION_CALLING = "SEARCH_REPLACE_FUNCTION_CALLING"
|
|
18
|
+
FULL_FILE_REWRITE = "FULL_FILE_REWRITE"
|
|
19
|
+
FUNCTION_CALLING = "FUNCTION_CALLING"
|
|
20
|
+
RAW_GPT = "RAW_GPT"
|
|
21
|
+
NATURAL_EDIT = "NATURAL_EDIT"
|
|
22
|
+
AGENT = "AGENT"
|
|
23
|
+
AGENT_STEP = "AGENT_STEP"
|
|
24
|
+
DATABASE = "DATABASE"
|
|
25
|
+
DATABASE_AGENT = "DATABASE_AGENT"
|
|
26
|
+
DATABASE_AGENT_STEP = "DATABASE_AGENT_STEP"
|
|
27
|
+
REVIEW_FILES = "REVIEW_FILES"
|
|
28
|
+
EXPLORE_CODEBASE = "EXPLORE_CODEBASE"
|
|
29
|
+
GENERATE_REVIEW = "GENERATE_REVIEW"
|
|
30
|
+
CUSTOM_STEP = "CUSTOM_STEP"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class StrategyInfo(BaseModel):
|
|
34
|
+
strategy_name: StrategyName
|
|
35
|
+
display_name: str
|
|
36
|
+
description: str
|
|
37
|
+
disabled: bool
|
|
38
|
+
display_order: int
|
|
39
|
+
is_agentic: bool
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
CHAT_MODE_DEFAULTS: dict[ChatMode, StrategyName] = {
|
|
43
|
+
ChatMode.DEFAULT: StrategyName.RAW_GPT,
|
|
44
|
+
ChatMode.CLI: StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML,
|
|
45
|
+
ChatMode.CLOUD: StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML,
|
|
46
|
+
ChatMode.DATABASE: StrategyName.DATABASE,
|
|
47
|
+
ChatMode.PYTHON_INTERPRETER: StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML,
|
|
48
|
+
ChatMode.WORKFLOW: StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML,
|
|
49
|
+
ChatMode.CODEBASE: StrategyName.READ_ONLY,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
STRATEGY_INFO_LIST: list[StrategyInfo] = [
|
|
53
|
+
StrategyInfo(
|
|
54
|
+
strategy_name=StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML,
|
|
55
|
+
display_name="Natural Edit Claude 3.7 XML",
|
|
56
|
+
description="A natural file editing strategy that uses Claude 3.7 XML.",
|
|
57
|
+
disabled=False,
|
|
58
|
+
display_order=-1,
|
|
59
|
+
is_agentic=False,
|
|
60
|
+
),
|
|
61
|
+
StrategyInfo(
|
|
62
|
+
strategy_name=StrategyName.READ_ONLY,
|
|
63
|
+
display_name="Read Only",
|
|
64
|
+
description="A strategy that allows you to read the codebase.",
|
|
65
|
+
disabled=False,
|
|
66
|
+
display_order=-1,
|
|
67
|
+
is_agentic=False,
|
|
68
|
+
),
|
|
69
|
+
StrategyInfo(
|
|
70
|
+
strategy_name=StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML_WITH_STEPS,
|
|
71
|
+
display_name="Natural Edit Claude 3.7 XML with Steps",
|
|
72
|
+
description="A natural file editing strategy that uses Claude 3.7 XML with steps.",
|
|
73
|
+
disabled=True,
|
|
74
|
+
display_order=0,
|
|
75
|
+
is_agentic=False,
|
|
76
|
+
),
|
|
77
|
+
StrategyInfo(
|
|
78
|
+
strategy_name=StrategyName.NATURAL_EDIT_CLAUDE_3_7_FUNCTION_CALLING,
|
|
79
|
+
display_name="Natural Edit Claude 3.7 Function Calling",
|
|
80
|
+
description="A natural file editing strategy that uses Claude 3.7 Function Calling.",
|
|
81
|
+
disabled=True,
|
|
82
|
+
display_order=0,
|
|
83
|
+
is_agentic=True,
|
|
84
|
+
),
|
|
85
|
+
StrategyInfo(
|
|
86
|
+
strategy_name=StrategyName.SEARCH_REPLACE_FUNCTION_CALLING,
|
|
87
|
+
display_name="Search Replace Function Calling",
|
|
88
|
+
description="A search replace strategy that uses Function Calling.",
|
|
89
|
+
disabled=True,
|
|
90
|
+
display_order=0,
|
|
91
|
+
is_agentic=True,
|
|
92
|
+
),
|
|
93
|
+
StrategyInfo(
|
|
94
|
+
strategy_name=StrategyName.FULL_FILE_REWRITE,
|
|
95
|
+
display_name="Full File Rewrites",
|
|
96
|
+
description="Rewrites the full file every time. Use this if your files are generally less than 300 lines.",
|
|
97
|
+
disabled=False,
|
|
98
|
+
display_order=2,
|
|
99
|
+
is_agentic=False,
|
|
100
|
+
),
|
|
101
|
+
StrategyInfo(
|
|
102
|
+
strategy_name=StrategyName.FUNCTION_CALLING,
|
|
103
|
+
display_name="Function Calling",
|
|
104
|
+
description="Using native function calling.",
|
|
105
|
+
disabled=True,
|
|
106
|
+
display_order=99,
|
|
107
|
+
is_agentic=False,
|
|
108
|
+
),
|
|
109
|
+
StrategyInfo(
|
|
110
|
+
strategy_name=StrategyName.RAW_GPT,
|
|
111
|
+
display_name="Raw GPT",
|
|
112
|
+
description="No description",
|
|
113
|
+
disabled=True,
|
|
114
|
+
display_order=99,
|
|
115
|
+
is_agentic=False,
|
|
116
|
+
),
|
|
117
|
+
StrategyInfo(
|
|
118
|
+
strategy_name=StrategyName.NATURAL_EDIT,
|
|
119
|
+
display_name="Natural Edit",
|
|
120
|
+
description="Deprecated",
|
|
121
|
+
disabled=True,
|
|
122
|
+
display_order=99,
|
|
123
|
+
is_agentic=False,
|
|
124
|
+
),
|
|
125
|
+
StrategyInfo(
|
|
126
|
+
strategy_name=StrategyName.AGENT,
|
|
127
|
+
display_name="Agent",
|
|
128
|
+
description="No description",
|
|
129
|
+
disabled=True,
|
|
130
|
+
display_order=99,
|
|
131
|
+
is_agentic=True,
|
|
132
|
+
),
|
|
133
|
+
StrategyInfo(
|
|
134
|
+
strategy_name=StrategyName.AGENT_STEP,
|
|
135
|
+
display_name="Agent Step",
|
|
136
|
+
description="No description",
|
|
137
|
+
disabled=True,
|
|
138
|
+
display_order=99,
|
|
139
|
+
is_agentic=False,
|
|
140
|
+
),
|
|
141
|
+
StrategyInfo(
|
|
142
|
+
strategy_name=StrategyName.DATABASE,
|
|
143
|
+
display_name="Database",
|
|
144
|
+
description="No description",
|
|
145
|
+
disabled=True,
|
|
146
|
+
display_order=99,
|
|
147
|
+
is_agentic=False,
|
|
148
|
+
),
|
|
149
|
+
StrategyInfo(
|
|
150
|
+
strategy_name=StrategyName.DATABASE_AGENT,
|
|
151
|
+
display_name="Database Agent",
|
|
152
|
+
description="No description",
|
|
153
|
+
disabled=True,
|
|
154
|
+
display_order=99,
|
|
155
|
+
is_agentic=True,
|
|
156
|
+
),
|
|
157
|
+
StrategyInfo(
|
|
158
|
+
strategy_name=StrategyName.DATABASE_AGENT_STEP,
|
|
159
|
+
display_name="Database Agent Step",
|
|
160
|
+
description="No description",
|
|
161
|
+
disabled=True,
|
|
162
|
+
display_order=99,
|
|
163
|
+
is_agentic=False,
|
|
164
|
+
),
|
|
165
|
+
StrategyInfo(
|
|
166
|
+
strategy_name=StrategyName.REVIEW_FILES,
|
|
167
|
+
display_name="Review Files",
|
|
168
|
+
description="No description",
|
|
169
|
+
disabled=True,
|
|
170
|
+
display_order=99,
|
|
171
|
+
is_agentic=False,
|
|
172
|
+
),
|
|
173
|
+
StrategyInfo(
|
|
174
|
+
strategy_name=StrategyName.EXPLORE_CODEBASE,
|
|
175
|
+
display_name="Explore Codebase",
|
|
176
|
+
description="No description",
|
|
177
|
+
disabled=True,
|
|
178
|
+
display_order=99,
|
|
179
|
+
is_agentic=False,
|
|
180
|
+
),
|
|
181
|
+
StrategyInfo(
|
|
182
|
+
strategy_name=StrategyName.GENERATE_REVIEW,
|
|
183
|
+
display_name="Generate Review",
|
|
184
|
+
description="No description",
|
|
185
|
+
disabled=True,
|
|
186
|
+
display_order=99,
|
|
187
|
+
is_agentic=False,
|
|
188
|
+
),
|
|
189
|
+
StrategyInfo(
|
|
190
|
+
strategy_name=StrategyName.CUSTOM_STEP,
|
|
191
|
+
display_name="Custom Step",
|
|
192
|
+
description="No description",
|
|
193
|
+
disabled=True,
|
|
194
|
+
display_order=99,
|
|
195
|
+
is_agentic=False,
|
|
196
|
+
),
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
ENABLED_STRATEGY_INFO_LIST: list[StrategyInfo] = [
|
|
201
|
+
StrategyInfo(
|
|
202
|
+
strategy_name=StrategyName.NATURAL_EDIT_CLAUDE_3_7_XML,
|
|
203
|
+
display_name="Natural Edit Claude 3.7 XML",
|
|
204
|
+
description="A natural file editing strategy that uses Claude 3.7 XML.",
|
|
205
|
+
disabled=False,
|
|
206
|
+
display_order=-1,
|
|
207
|
+
is_agentic=False,
|
|
208
|
+
),
|
|
209
|
+
StrategyInfo(
|
|
210
|
+
strategy_name=StrategyName.READ_ONLY,
|
|
211
|
+
display_name="Read Only",
|
|
212
|
+
description="A strategy that allows you to read the codebase.",
|
|
213
|
+
disabled=False,
|
|
214
|
+
display_order=-1,
|
|
215
|
+
is_agentic=False,
|
|
216
|
+
),
|
|
217
|
+
StrategyInfo(
|
|
218
|
+
strategy_name=StrategyName.FULL_FILE_REWRITE,
|
|
219
|
+
display_name="Full File Rewrites",
|
|
220
|
+
description="Rewrites the full file every time. Use this if your files are generally less than 300 lines.",
|
|
221
|
+
disabled=False,
|
|
222
|
+
display_order=2,
|
|
223
|
+
is_agentic=False,
|
|
224
|
+
),
|
|
225
|
+
]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Authentication and Login System Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
The authentication system in Exponent is built around API keys and GraphQL-based authentication. The system supports multiple environments (development, staging, production) with different API endpoints and authentication mechanisms.
|
|
5
|
+
|
|
6
|
+
## Key Components
|
|
7
|
+
|
|
8
|
+
### 1. Configuration and Settings
|
|
9
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/config.py`
|
|
10
|
+
|
|
11
|
+
The settings system manages:
|
|
12
|
+
- API keys for different environments (development, staging, production)
|
|
13
|
+
- Base URLs for different services
|
|
14
|
+
- Configuration storage in `~/.config/exponent/config.json`
|
|
15
|
+
|
|
16
|
+
### 2. Login Command
|
|
17
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/commands/config_commands.py`
|
|
18
|
+
|
|
19
|
+
The login command:
|
|
20
|
+
- Accepts an API key via `indent login --key <API-KEY>`
|
|
21
|
+
- Verifies the API key with the server
|
|
22
|
+
- Stores the verified key in the config file
|
|
23
|
+
|
|
24
|
+
### 3. Authentication Flow
|
|
25
|
+
|
|
26
|
+
#### Initial Authentication
|
|
27
|
+
1. When a command is run, the system checks for an API key
|
|
28
|
+
2. If no API key is found:
|
|
29
|
+
- In SSH session: Shows message to run `indent login --key <API-KEY>`
|
|
30
|
+
- Otherwise: Redirects to `<base_url>/cli` for web-based login
|
|
31
|
+
|
|
32
|
+
#### API Key Verification
|
|
33
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/commands/common.py`
|
|
34
|
+
|
|
35
|
+
The system verifies API keys through:
|
|
36
|
+
1. GraphQL mutation `SET_LOGIN_COMPLETE_MUTATION`
|
|
37
|
+
2. Verification of returned API key matching the provided key
|
|
38
|
+
|
|
39
|
+
#### API Key Refresh
|
|
40
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/commands/config_commands.py`
|
|
41
|
+
|
|
42
|
+
Users can refresh their API key using:
|
|
43
|
+
- Command: `exponent config refresh-key`
|
|
44
|
+
- Uses `REFRESH_API_KEY_MUTATION` GraphQL mutation
|
|
45
|
+
- Automatically updates the stored API key
|
|
46
|
+
|
|
47
|
+
### 4. GraphQL Authentication
|
|
48
|
+
|
|
49
|
+
#### Client Setup
|
|
50
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/graphql/client.py`
|
|
51
|
+
|
|
52
|
+
The GraphQL client:
|
|
53
|
+
- Adds API key to HTTP headers for REST calls
|
|
54
|
+
- Includes API key in WebSocket init payload
|
|
55
|
+
- Handles both HTTP and WebSocket connections
|
|
56
|
+
|
|
57
|
+
#### Key Mutations and Subscriptions
|
|
58
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/graphql/mutations.py`
|
|
59
|
+
|
|
60
|
+
Important GraphQL operations:
|
|
61
|
+
```graphql
|
|
62
|
+
SET_LOGIN_COMPLETE_MUTATION
|
|
63
|
+
REFRESH_API_KEY_MUTATION
|
|
64
|
+
AUTHENTICATED_USER_SUBSCRIPTION
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 5. Environment Support
|
|
68
|
+
**Location**: `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/config.py`
|
|
69
|
+
|
|
70
|
+
Supports multiple environments:
|
|
71
|
+
- Development: `localhost:3000` (API), `localhost:8000` (WebSocket)
|
|
72
|
+
- Staging: `staging.exponent.run`
|
|
73
|
+
- Production: `exponent.run`
|
|
74
|
+
|
|
75
|
+
## Security Considerations
|
|
76
|
+
|
|
77
|
+
1. API Key Storage
|
|
78
|
+
- Keys stored in `~/.config/exponent/config.json`
|
|
79
|
+
- Separate keys for different environments
|
|
80
|
+
|
|
81
|
+
2. SSL/TLS Security
|
|
82
|
+
- System checks for SSL certificates
|
|
83
|
+
- Can install certificates if missing (macOS specific)
|
|
84
|
+
- Uses `certifi` for certificate verification
|
|
85
|
+
|
|
86
|
+
## Error Handling
|
|
87
|
+
|
|
88
|
+
The system handles various authentication errors:
|
|
89
|
+
- Invalid API keys
|
|
90
|
+
- Network connection issues
|
|
91
|
+
- SSL certificate problems
|
|
92
|
+
- Environment-specific configuration issues
|
|
93
|
+
|
|
94
|
+
## Related Files (Absolute Paths)
|
|
95
|
+
|
|
96
|
+
1. `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/config.py`
|
|
97
|
+
- Core configuration and settings management
|
|
98
|
+
|
|
99
|
+
2. `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/commands/config_commands.py`
|
|
100
|
+
- Login and API key management commands
|
|
101
|
+
|
|
102
|
+
3. `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/commands/common.py`
|
|
103
|
+
- Authentication helpers and utilities
|
|
104
|
+
|
|
105
|
+
4. `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/graphql/client.py`
|
|
106
|
+
- GraphQL client implementation
|
|
107
|
+
|
|
108
|
+
5. `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/graphql/mutations.py`
|
|
109
|
+
- Authentication-related GraphQL mutations
|
|
110
|
+
|
|
111
|
+
6. `/Users/dkzlv/Projects/exponent-wrapper/exponent/python_modules/exponent/exponent/core/graphql/subscriptions.py`
|
|
112
|
+
- Authentication-related GraphQL subscriptions
|
exponent/py.typed
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# This is a typing sentinel. It's required to make type checkers regard this as a typed library when the library is installed as a dependency.
|
|
2
|
+
# since this code is installed inside the exponent_server package as well, via a dependency, we have to ensure this sentinel is in place.
|
|
3
|
+
|
|
4
|
+
# further reading: https://peps.python.org/pep-0561/
|
|
File without changes
|