namel3ss 0.1.0a0__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.
- namel3ss/__init__.py +4 -0
- namel3ss/ast/__init__.py +5 -0
- namel3ss/ast/agents.py +13 -0
- namel3ss/ast/ai.py +23 -0
- namel3ss/ast/base.py +10 -0
- namel3ss/ast/expressions.py +55 -0
- namel3ss/ast/nodes.py +86 -0
- namel3ss/ast/pages.py +43 -0
- namel3ss/ast/program.py +22 -0
- namel3ss/ast/records.py +27 -0
- namel3ss/ast/statements.py +107 -0
- namel3ss/ast/tool.py +11 -0
- namel3ss/cli/__init__.py +2 -0
- namel3ss/cli/actions_mode.py +39 -0
- namel3ss/cli/app_loader.py +22 -0
- namel3ss/cli/commands/action.py +27 -0
- namel3ss/cli/commands/run.py +43 -0
- namel3ss/cli/commands/ui.py +26 -0
- namel3ss/cli/commands/validate.py +23 -0
- namel3ss/cli/format_mode.py +30 -0
- namel3ss/cli/io/json_io.py +19 -0
- namel3ss/cli/io/read_source.py +16 -0
- namel3ss/cli/json_io.py +21 -0
- namel3ss/cli/lint_mode.py +29 -0
- namel3ss/cli/main.py +135 -0
- namel3ss/cli/new_mode.py +146 -0
- namel3ss/cli/runner.py +28 -0
- namel3ss/cli/studio_mode.py +22 -0
- namel3ss/cli/ui_mode.py +14 -0
- namel3ss/config/__init__.py +4 -0
- namel3ss/config/dotenv.py +33 -0
- namel3ss/config/loader.py +83 -0
- namel3ss/config/model.py +49 -0
- namel3ss/errors/__init__.py +2 -0
- namel3ss/errors/base.py +34 -0
- namel3ss/errors/render.py +22 -0
- namel3ss/format/__init__.py +3 -0
- namel3ss/format/formatter.py +18 -0
- namel3ss/format/rules.py +97 -0
- namel3ss/ir/__init__.py +3 -0
- namel3ss/ir/lowering/__init__.py +4 -0
- namel3ss/ir/lowering/agents.py +42 -0
- namel3ss/ir/lowering/ai.py +45 -0
- namel3ss/ir/lowering/expressions.py +49 -0
- namel3ss/ir/lowering/flow.py +21 -0
- namel3ss/ir/lowering/pages.py +48 -0
- namel3ss/ir/lowering/program.py +34 -0
- namel3ss/ir/lowering/records.py +25 -0
- namel3ss/ir/lowering/statements.py +122 -0
- namel3ss/ir/lowering/tools.py +16 -0
- namel3ss/ir/model/__init__.py +50 -0
- namel3ss/ir/model/agents.py +33 -0
- namel3ss/ir/model/ai.py +31 -0
- namel3ss/ir/model/base.py +20 -0
- namel3ss/ir/model/expressions.py +50 -0
- namel3ss/ir/model/pages.py +43 -0
- namel3ss/ir/model/program.py +28 -0
- namel3ss/ir/model/statements.py +76 -0
- namel3ss/ir/model/tools.py +11 -0
- namel3ss/ir/nodes.py +88 -0
- namel3ss/lexer/__init__.py +2 -0
- namel3ss/lexer/lexer.py +152 -0
- namel3ss/lexer/tokens.py +98 -0
- namel3ss/lint/__init__.py +4 -0
- namel3ss/lint/engine.py +125 -0
- namel3ss/lint/semantic.py +45 -0
- namel3ss/lint/text_scan.py +70 -0
- namel3ss/lint/types.py +22 -0
- namel3ss/parser/__init__.py +3 -0
- namel3ss/parser/agent.py +78 -0
- namel3ss/parser/ai.py +113 -0
- namel3ss/parser/constraints.py +37 -0
- namel3ss/parser/core.py +166 -0
- namel3ss/parser/expressions.py +105 -0
- namel3ss/parser/flow.py +37 -0
- namel3ss/parser/pages.py +76 -0
- namel3ss/parser/program.py +45 -0
- namel3ss/parser/records.py +66 -0
- namel3ss/parser/statements/__init__.py +27 -0
- namel3ss/parser/statements/control_flow.py +116 -0
- namel3ss/parser/statements/core.py +66 -0
- namel3ss/parser/statements/data.py +17 -0
- namel3ss/parser/statements/letset.py +22 -0
- namel3ss/parser/statements.py +1 -0
- namel3ss/parser/tokens.py +35 -0
- namel3ss/parser/tool.py +29 -0
- namel3ss/runtime/__init__.py +3 -0
- namel3ss/runtime/ai/http/client.py +24 -0
- namel3ss/runtime/ai/mock_provider.py +5 -0
- namel3ss/runtime/ai/provider.py +29 -0
- namel3ss/runtime/ai/providers/__init__.py +18 -0
- namel3ss/runtime/ai/providers/_shared/errors.py +20 -0
- namel3ss/runtime/ai/providers/_shared/parse.py +18 -0
- namel3ss/runtime/ai/providers/anthropic.py +55 -0
- namel3ss/runtime/ai/providers/gemini.py +50 -0
- namel3ss/runtime/ai/providers/mistral.py +51 -0
- namel3ss/runtime/ai/providers/mock.py +23 -0
- namel3ss/runtime/ai/providers/ollama.py +39 -0
- namel3ss/runtime/ai/providers/openai.py +55 -0
- namel3ss/runtime/ai/providers/registry.py +38 -0
- namel3ss/runtime/ai/trace.py +18 -0
- namel3ss/runtime/executor/__init__.py +3 -0
- namel3ss/runtime/executor/agents.py +91 -0
- namel3ss/runtime/executor/ai_runner.py +90 -0
- namel3ss/runtime/executor/api.py +54 -0
- namel3ss/runtime/executor/assign.py +40 -0
- namel3ss/runtime/executor/context.py +31 -0
- namel3ss/runtime/executor/executor.py +77 -0
- namel3ss/runtime/executor/expr_eval.py +110 -0
- namel3ss/runtime/executor/records_ops.py +64 -0
- namel3ss/runtime/executor/result.py +13 -0
- namel3ss/runtime/executor/signals.py +6 -0
- namel3ss/runtime/executor/statements.py +99 -0
- namel3ss/runtime/memory/manager.py +52 -0
- namel3ss/runtime/memory/profile.py +17 -0
- namel3ss/runtime/memory/semantic.py +20 -0
- namel3ss/runtime/memory/short_term.py +18 -0
- namel3ss/runtime/records/service.py +105 -0
- namel3ss/runtime/store/__init__.py +2 -0
- namel3ss/runtime/store/memory_store.py +62 -0
- namel3ss/runtime/tools/registry.py +13 -0
- namel3ss/runtime/ui/__init__.py +2 -0
- namel3ss/runtime/ui/actions.py +124 -0
- namel3ss/runtime/validators/__init__.py +2 -0
- namel3ss/runtime/validators/constraints.py +126 -0
- namel3ss/schema/__init__.py +2 -0
- namel3ss/schema/records.py +52 -0
- namel3ss/studio/__init__.py +4 -0
- namel3ss/studio/api.py +115 -0
- namel3ss/studio/edit/__init__.py +3 -0
- namel3ss/studio/edit/ops.py +80 -0
- namel3ss/studio/edit/selectors.py +74 -0
- namel3ss/studio/edit/transform.py +39 -0
- namel3ss/studio/server.py +175 -0
- namel3ss/studio/session.py +11 -0
- namel3ss/studio/web/app.js +248 -0
- namel3ss/studio/web/index.html +44 -0
- namel3ss/studio/web/styles.css +42 -0
- namel3ss/templates/__init__.py +3 -0
- namel3ss/templates/__pycache__/__init__.cpython-312.pyc +0 -0
- namel3ss/templates/ai_assistant/.gitignore +1 -0
- namel3ss/templates/ai_assistant/README.md +10 -0
- namel3ss/templates/ai_assistant/app.ai +30 -0
- namel3ss/templates/crud/.gitignore +1 -0
- namel3ss/templates/crud/README.md +10 -0
- namel3ss/templates/crud/app.ai +26 -0
- namel3ss/templates/multi_agent/.gitignore +1 -0
- namel3ss/templates/multi_agent/README.md +10 -0
- namel3ss/templates/multi_agent/app.ai +43 -0
- namel3ss/ui/__init__.py +2 -0
- namel3ss/ui/manifest.py +220 -0
- namel3ss/utils/__init__.py +2 -0
- namel3ss-0.1.0a0.dist-info/METADATA +123 -0
- namel3ss-0.1.0a0.dist-info/RECORD +157 -0
- namel3ss-0.1.0a0.dist-info/WHEEL +5 -0
- namel3ss-0.1.0a0.dist-info/entry_points.txt +2 -0
- namel3ss-0.1.0a0.dist-info/top_level.txt +1 -0
namel3ss/__init__.py
ADDED
namel3ss/ast/__init__.py
ADDED
namel3ss/ast/agents.py
ADDED
namel3ss/ast/ai.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.base import Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class AIMemory(Node):
|
|
11
|
+
short_term: int = 0
|
|
12
|
+
semantic: bool = False
|
|
13
|
+
profile: bool = False
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class AIDecl(Node):
|
|
18
|
+
name: str
|
|
19
|
+
model: str
|
|
20
|
+
provider: str | None
|
|
21
|
+
system_prompt: Optional[str]
|
|
22
|
+
exposed_tools: List[str]
|
|
23
|
+
memory: AIMemory
|
namel3ss/ast/base.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional, Union
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.base import Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Expression(Node):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class Literal(Expression):
|
|
16
|
+
value: Union[str, int, bool]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class VarReference(Expression):
|
|
21
|
+
name: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class AttrAccess(Expression):
|
|
26
|
+
base: str
|
|
27
|
+
attrs: List[str]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class StatePath(Expression):
|
|
32
|
+
path: List[str]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class UnaryOp(Expression):
|
|
37
|
+
op: str
|
|
38
|
+
operand: Expression
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class BinaryOp(Expression):
|
|
43
|
+
op: str
|
|
44
|
+
left: Expression
|
|
45
|
+
right: Expression
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class Comparison(Expression):
|
|
50
|
+
kind: str # eq, gt, lt
|
|
51
|
+
left: Expression
|
|
52
|
+
right: Expression
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
Assignable = Union[VarReference, StatePath]
|
namel3ss/ast/nodes.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional, Union
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.agents import AgentDecl
|
|
7
|
+
from namel3ss.ast.ai import AIDecl, AIMemory
|
|
8
|
+
from namel3ss.ast.base import Node
|
|
9
|
+
from namel3ss.ast.expressions import (
|
|
10
|
+
Assignable,
|
|
11
|
+
AttrAccess,
|
|
12
|
+
BinaryOp,
|
|
13
|
+
Comparison,
|
|
14
|
+
Expression,
|
|
15
|
+
Literal,
|
|
16
|
+
StatePath,
|
|
17
|
+
UnaryOp,
|
|
18
|
+
VarReference,
|
|
19
|
+
)
|
|
20
|
+
from namel3ss.ast.pages import ButtonItem, FormItem, PageDecl, PageItem, TableItem, TextItem, TitleItem
|
|
21
|
+
from namel3ss.ast.program import Flow, Program
|
|
22
|
+
from namel3ss.ast.statements import (
|
|
23
|
+
AskAIStmt,
|
|
24
|
+
Find,
|
|
25
|
+
ForEach,
|
|
26
|
+
If,
|
|
27
|
+
Let,
|
|
28
|
+
Match,
|
|
29
|
+
MatchCase,
|
|
30
|
+
ParallelAgentEntry,
|
|
31
|
+
Repeat,
|
|
32
|
+
Return,
|
|
33
|
+
RunAgentStmt,
|
|
34
|
+
RunAgentsParallelStmt,
|
|
35
|
+
Save,
|
|
36
|
+
Set,
|
|
37
|
+
Statement,
|
|
38
|
+
TryCatch,
|
|
39
|
+
)
|
|
40
|
+
from namel3ss.ast.tool import ToolDecl
|
|
41
|
+
from namel3ss.ast.records import FieldConstraint, FieldDecl, RecordDecl
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"Node",
|
|
45
|
+
"Flow",
|
|
46
|
+
"Program",
|
|
47
|
+
"Statement",
|
|
48
|
+
"Let",
|
|
49
|
+
"Set",
|
|
50
|
+
"If",
|
|
51
|
+
"Return",
|
|
52
|
+
"AskAIStmt",
|
|
53
|
+
"RunAgentStmt",
|
|
54
|
+
"ParallelAgentEntry",
|
|
55
|
+
"RunAgentsParallelStmt",
|
|
56
|
+
"Repeat",
|
|
57
|
+
"ForEach",
|
|
58
|
+
"MatchCase",
|
|
59
|
+
"Match",
|
|
60
|
+
"TryCatch",
|
|
61
|
+
"Save",
|
|
62
|
+
"Find",
|
|
63
|
+
"Expression",
|
|
64
|
+
"Literal",
|
|
65
|
+
"VarReference",
|
|
66
|
+
"AttrAccess",
|
|
67
|
+
"StatePath",
|
|
68
|
+
"UnaryOp",
|
|
69
|
+
"BinaryOp",
|
|
70
|
+
"Comparison",
|
|
71
|
+
"Assignable",
|
|
72
|
+
"FieldConstraint",
|
|
73
|
+
"FieldDecl",
|
|
74
|
+
"RecordDecl",
|
|
75
|
+
"PageItem",
|
|
76
|
+
"TitleItem",
|
|
77
|
+
"TextItem",
|
|
78
|
+
"FormItem",
|
|
79
|
+
"TableItem",
|
|
80
|
+
"ButtonItem",
|
|
81
|
+
"PageDecl",
|
|
82
|
+
"AIDecl",
|
|
83
|
+
"AIMemory",
|
|
84
|
+
"ToolDecl",
|
|
85
|
+
"AgentDecl",
|
|
86
|
+
]
|
namel3ss/ast/pages.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.base import Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class PageItem(Node):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class TitleItem(PageItem):
|
|
16
|
+
value: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class TextItem(PageItem):
|
|
21
|
+
value: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class FormItem(PageItem):
|
|
26
|
+
record_name: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class TableItem(PageItem):
|
|
31
|
+
record_name: str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class ButtonItem(PageItem):
|
|
36
|
+
label: str
|
|
37
|
+
flow_name: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class PageDecl(Node):
|
|
42
|
+
name: str
|
|
43
|
+
items: List[PageItem]
|
namel3ss/ast/program.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.base import Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Flow(Node):
|
|
11
|
+
name: str
|
|
12
|
+
body: List["Statement"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Program(Node):
|
|
17
|
+
records: List["RecordDecl"]
|
|
18
|
+
flows: List[Flow]
|
|
19
|
+
pages: List["PageDecl"]
|
|
20
|
+
ais: List["AIDecl"]
|
|
21
|
+
tools: List["ToolDecl"]
|
|
22
|
+
agents: List["AgentDecl"]
|
namel3ss/ast/records.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.base import Node
|
|
7
|
+
from namel3ss.ast.expressions import Expression
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class FieldConstraint(Node):
|
|
12
|
+
kind: str # present, unique, gt, lt, pattern, len_min, len_max
|
|
13
|
+
expression: Optional[Expression] = None
|
|
14
|
+
pattern: Optional[str] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class FieldDecl(Node):
|
|
19
|
+
name: str
|
|
20
|
+
type_name: str
|
|
21
|
+
constraint: Optional[FieldConstraint]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class RecordDecl(Node):
|
|
26
|
+
name: str
|
|
27
|
+
fields: List[FieldDecl]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from namel3ss.ast.base import Node
|
|
7
|
+
from namel3ss.ast.expressions import Assignable, Expression
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Statement(Node):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Let(Statement):
|
|
17
|
+
name: str
|
|
18
|
+
expression: Expression
|
|
19
|
+
constant: bool = False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class Set(Statement):
|
|
24
|
+
target: Assignable
|
|
25
|
+
expression: Expression
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class If(Statement):
|
|
30
|
+
condition: Expression
|
|
31
|
+
then_body: List[Statement]
|
|
32
|
+
else_body: List[Statement]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class Return(Statement):
|
|
37
|
+
expression: Expression
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class AskAIStmt(Statement):
|
|
42
|
+
ai_name: str
|
|
43
|
+
input_expr: Expression
|
|
44
|
+
target: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class RunAgentStmt(Statement):
|
|
49
|
+
agent_name: str
|
|
50
|
+
input_expr: Expression
|
|
51
|
+
target: str
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class ParallelAgentEntry(Node):
|
|
56
|
+
agent_name: str
|
|
57
|
+
input_expr: Expression
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class RunAgentsParallelStmt(Statement):
|
|
62
|
+
entries: List[ParallelAgentEntry]
|
|
63
|
+
target: str
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class Repeat(Statement):
|
|
68
|
+
count: Expression
|
|
69
|
+
body: List[Statement]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class ForEach(Statement):
|
|
74
|
+
name: str
|
|
75
|
+
iterable: Expression
|
|
76
|
+
body: List[Statement]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class MatchCase(Node):
|
|
81
|
+
pattern: Expression
|
|
82
|
+
body: List[Statement]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class Match(Statement):
|
|
87
|
+
expression: Expression
|
|
88
|
+
cases: List[MatchCase]
|
|
89
|
+
otherwise: Optional[List[Statement]]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class TryCatch(Statement):
|
|
94
|
+
try_body: List[Statement]
|
|
95
|
+
catch_var: str
|
|
96
|
+
catch_body: List[Statement]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class Save(Statement):
|
|
101
|
+
record_name: str
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class Find(Statement):
|
|
106
|
+
record_name: str
|
|
107
|
+
predicate: Expression
|
namel3ss/ast/tool.py
ADDED
namel3ss/cli/__init__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from namel3ss.runtime.store.memory_store import MemoryStore
|
|
4
|
+
from namel3ss.ui.manifest import build_manifest
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def list_actions(program_ir, json_mode: bool) -> tuple[dict | None, str | None]:
|
|
8
|
+
manifest = build_manifest(program_ir, state={}, store=MemoryStore())
|
|
9
|
+
actions = manifest.get("actions", {})
|
|
10
|
+
sorted_ids = sorted(actions.keys())
|
|
11
|
+
if json_mode:
|
|
12
|
+
data = []
|
|
13
|
+
for action_id in sorted_ids:
|
|
14
|
+
entry = actions[action_id]
|
|
15
|
+
item = {"id": action_id, "type": entry.get("type")}
|
|
16
|
+
if entry.get("type") == "call_flow":
|
|
17
|
+
item["flow"] = entry.get("flow")
|
|
18
|
+
if entry.get("type") == "submit_form":
|
|
19
|
+
item["record"] = entry.get("record")
|
|
20
|
+
data.append(item)
|
|
21
|
+
return (
|
|
22
|
+
{
|
|
23
|
+
"ok": True,
|
|
24
|
+
"count": len(data),
|
|
25
|
+
"actions": data,
|
|
26
|
+
},
|
|
27
|
+
None,
|
|
28
|
+
)
|
|
29
|
+
lines = []
|
|
30
|
+
for action_id in sorted_ids:
|
|
31
|
+
entry = actions[action_id]
|
|
32
|
+
details: list[str] = []
|
|
33
|
+
if entry.get("type") == "call_flow" and entry.get("flow"):
|
|
34
|
+
details.append(f"flow={entry['flow']}")
|
|
35
|
+
if entry.get("type") == "submit_form" and entry.get("record"):
|
|
36
|
+
details.append(f"record={entry['record']}")
|
|
37
|
+
detail_str = f" {' '.join(details)}" if details else ""
|
|
38
|
+
lines.append(f"{action_id} {entry.get('type')} {detail_str}".rstrip())
|
|
39
|
+
return None, "\n".join(lines)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
from namel3ss.ir.nodes import lower_program
|
|
7
|
+
from namel3ss.parser.core import parse
|
|
8
|
+
from namel3ss.config.dotenv import apply_dotenv, load_dotenv_for_path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_program(path_str: str) -> tuple[object, str]:
|
|
12
|
+
path = Path(path_str)
|
|
13
|
+
if path.suffix != ".ai":
|
|
14
|
+
raise Namel3ssError("Input file must have .ai extension")
|
|
15
|
+
apply_dotenv(load_dotenv_for_path(str(path)))
|
|
16
|
+
try:
|
|
17
|
+
source = path.read_text(encoding="utf-8")
|
|
18
|
+
except FileNotFoundError as err:
|
|
19
|
+
raise Namel3ssError(f"File not found: {path}") from err
|
|
20
|
+
ast_program = parse(source)
|
|
21
|
+
program_ir = lower_program(ast_program)
|
|
22
|
+
return program_ir, source
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
from namel3ss.errors.render import format_error
|
|
7
|
+
from namel3ss.ir.nodes import lower_program
|
|
8
|
+
from namel3ss.parser.core import parse
|
|
9
|
+
from namel3ss.runtime.store.memory_store import MemoryStore
|
|
10
|
+
from namel3ss.runtime.ui.actions import handle_action
|
|
11
|
+
from namel3ss.cli.io.json_io import dumps_pretty, parse_json
|
|
12
|
+
from namel3ss.cli.io.read_source import read_source
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(args) -> int:
|
|
16
|
+
source = ""
|
|
17
|
+
try:
|
|
18
|
+
source, _ = read_source(args.path)
|
|
19
|
+
ast_program = parse(source)
|
|
20
|
+
program_ir = lower_program(ast_program)
|
|
21
|
+
payload = parse_json(args.payload or "{}")
|
|
22
|
+
response = handle_action(program_ir, action_id=args.id, payload=payload, state={}, store=MemoryStore())
|
|
23
|
+
print(dumps_pretty(response))
|
|
24
|
+
return 0
|
|
25
|
+
except Namel3ssError as err:
|
|
26
|
+
print(format_error(err, source), file=sys.stderr)
|
|
27
|
+
return 1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
from namel3ss.errors.render import format_error
|
|
7
|
+
from namel3ss.ir.nodes import lower_program
|
|
8
|
+
from namel3ss.parser.core import parse
|
|
9
|
+
from namel3ss.runtime.executor import execute_program_flow
|
|
10
|
+
from namel3ss.runtime.store.memory_store import MemoryStore
|
|
11
|
+
from namel3ss.cli.io.json_io import dumps_pretty
|
|
12
|
+
from namel3ss.cli.io.read_source import read_source
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(args) -> int:
|
|
16
|
+
source = ""
|
|
17
|
+
try:
|
|
18
|
+
source, path = read_source(args.path)
|
|
19
|
+
ast_program = parse(source)
|
|
20
|
+
program_ir = lower_program(ast_program)
|
|
21
|
+
flow_name = _select_flow(program_ir, args.flow)
|
|
22
|
+
result = execute_program_flow(program_ir, flow_name, state={}, input={}, store=MemoryStore())
|
|
23
|
+
traces = [_trace_to_dict(t) for t in result.traces]
|
|
24
|
+
output = {"ok": True, "state": result.state, "result": result.last_value, "traces": traces}
|
|
25
|
+
print(dumps_pretty(output))
|
|
26
|
+
return 0
|
|
27
|
+
except Namel3ssError as err:
|
|
28
|
+
print(format_error(err, source), file=sys.stderr)
|
|
29
|
+
return 1
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _select_flow(program_ir, flow_flag: str | None) -> str:
|
|
33
|
+
if flow_flag:
|
|
34
|
+
return flow_flag
|
|
35
|
+
if len(program_ir.flows) == 1:
|
|
36
|
+
return program_ir.flows[0].name
|
|
37
|
+
raise Namel3ssError("Multiple flows found; specify --flow")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _trace_to_dict(trace) -> dict:
|
|
41
|
+
if hasattr(trace, "__dict__"):
|
|
42
|
+
return trace.__dict__
|
|
43
|
+
return trace if isinstance(trace, dict) else {"value": trace}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
from namel3ss.errors.render import format_error
|
|
7
|
+
from namel3ss.ir.nodes import lower_program
|
|
8
|
+
from namel3ss.parser.core import parse
|
|
9
|
+
from namel3ss.runtime.store.memory_store import MemoryStore
|
|
10
|
+
from namel3ss.ui.manifest import build_manifest
|
|
11
|
+
from namel3ss.cli.io.json_io import dumps_pretty
|
|
12
|
+
from namel3ss.cli.io.read_source import read_source
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(args) -> int:
|
|
16
|
+
source = ""
|
|
17
|
+
try:
|
|
18
|
+
source, _ = read_source(args.path)
|
|
19
|
+
ast_program = parse(source)
|
|
20
|
+
program_ir = lower_program(ast_program)
|
|
21
|
+
manifest = build_manifest(program_ir, state={}, store=MemoryStore())
|
|
22
|
+
print(dumps_pretty(manifest))
|
|
23
|
+
return 0
|
|
24
|
+
except Namel3ssError as err:
|
|
25
|
+
print(format_error(err, source), file=sys.stderr)
|
|
26
|
+
return 1
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
from namel3ss.errors.render import format_error
|
|
7
|
+
from namel3ss.ir.nodes import lower_program
|
|
8
|
+
from namel3ss.parser.core import parse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def run(args) -> int:
|
|
12
|
+
source = ""
|
|
13
|
+
try:
|
|
14
|
+
from namel3ss.cli.io.read_source import read_source
|
|
15
|
+
|
|
16
|
+
source, _ = read_source(args.path)
|
|
17
|
+
ast_program = parse(source)
|
|
18
|
+
lower_program(ast_program)
|
|
19
|
+
print("Validation succeeded.")
|
|
20
|
+
return 0
|
|
21
|
+
except Namel3ssError as err:
|
|
22
|
+
print(format_error(err, source), file=sys.stderr)
|
|
23
|
+
return 1
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
from namel3ss.errors.render import format_error
|
|
7
|
+
from namel3ss.format.formatter import format_source
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def run_format(path_str: str, check_only: bool) -> int:
|
|
11
|
+
path = Path(path_str)
|
|
12
|
+
if path.suffix != ".ai":
|
|
13
|
+
raise Namel3ssError("Input file must have .ai extension")
|
|
14
|
+
try:
|
|
15
|
+
source = path.read_text(encoding="utf-8")
|
|
16
|
+
except FileNotFoundError as err:
|
|
17
|
+
raise Namel3ssError(f"File not found: {path}") from err
|
|
18
|
+
formatted = format_source(source)
|
|
19
|
+
if check_only:
|
|
20
|
+
if formatted == source:
|
|
21
|
+
print("OK")
|
|
22
|
+
return 0
|
|
23
|
+
print("Needs formatting")
|
|
24
|
+
return 1
|
|
25
|
+
if formatted == source:
|
|
26
|
+
print("Already formatted")
|
|
27
|
+
return 0
|
|
28
|
+
path.write_text(formatted, encoding="utf-8")
|
|
29
|
+
print("Formatted")
|
|
30
|
+
return 0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_json(text: str) -> dict:
|
|
9
|
+
try:
|
|
10
|
+
data = json.loads(text) if text else {}
|
|
11
|
+
except json.JSONDecodeError as exc:
|
|
12
|
+
raise Namel3ssError(f"Invalid JSON payload: {exc.msg}") from exc
|
|
13
|
+
if not isinstance(data, dict):
|
|
14
|
+
raise Namel3ssError("Payload JSON must be an object")
|
|
15
|
+
return data
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def dumps_pretty(obj: object) -> str:
|
|
19
|
+
return json.dumps(obj, indent=2, ensure_ascii=False)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from namel3ss.errors.base import Namel3ssError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def read_source(path_str: str) -> tuple[str, str]:
|
|
9
|
+
path = Path(path_str)
|
|
10
|
+
if path.suffix != ".ai":
|
|
11
|
+
raise Namel3ssError("Input file must have .ai extension")
|
|
12
|
+
try:
|
|
13
|
+
text = path.read_text(encoding="utf-8")
|
|
14
|
+
except FileNotFoundError as err:
|
|
15
|
+
raise Namel3ssError(f"File not found: {path}") from err
|
|
16
|
+
return text, str(path)
|