@lamentis/naome 1.3.7 → 1.3.8
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.
- package/Cargo.lock +2 -2
- package/README.md +5 -0
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/context/select.rs +58 -4
- package/crates/naome-core/src/intent/classifier.rs +56 -81
- package/crates/naome-core/src/intent/envelope.rs +173 -19
- package/crates/naome-core/src/intent/legacy_response.rs +2 -0
- package/crates/naome-core/src/intent/model.rs +6 -0
- package/crates/naome-core/src/intent/resolver.rs +25 -0
- package/crates/naome-core/src/intent/risk.rs +11 -1
- package/crates/naome-core/src/intent.rs +1 -1
- package/crates/naome-core/src/route/context.rs +8 -0
- package/crates/naome-core/tests/context.rs +92 -0
- package/crates/naome-core/tests/intent.rs +98 -18
- package/crates/naome-core/tests/intent_support/mod.rs +39 -1
- package/crates/naome-core/tests/intent_v2.rs +299 -10
- package/crates/naome-core/tests/repo_support/routes.rs +8 -2
- package/crates/naome-core/tests/route_baseline.rs +29 -0
- package/crates/naome-core/tests/route_completion.rs +26 -5
- package/crates/naome-core/tests/route_harness_refresh.rs +7 -1
- package/crates/naome-core/tests/route_user_diff.rs +1 -1
- package/crates/naome-core/tests/task_state_compact.rs +7 -1
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/templates/naome-root/.naome/manifest.json +2 -2
- package/templates/naome-root/docs/naome/agent-workflow.md +14 -5
- package/templates/naome-root/docs/naome/architecture.md +9 -0
- package/crates/naome-core/src/intent/patterns.rs +0 -170
|
@@ -89,6 +89,20 @@ fn resolve_policy(
|
|
|
89
89
|
} else if prompt_intent == IntentKind::Unsafe {
|
|
90
90
|
reason_codes.push("winning_rule:unsafe_intent_precedence".to_string());
|
|
91
91
|
unsafe_policy()
|
|
92
|
+
} else if prompt_intent == IntentKind::PromptNormalizationRequired {
|
|
93
|
+
(
|
|
94
|
+
"normalize_prompt_first",
|
|
95
|
+
true,
|
|
96
|
+
"NAOME needs a structured prompt envelope before routing or mutating repository state.",
|
|
97
|
+
"Normalize the user prompt into the deterministic NAOME prompt envelope, then rerun routing.",
|
|
98
|
+
)
|
|
99
|
+
} else if prompt_intent == IntentKind::Advisory {
|
|
100
|
+
(
|
|
101
|
+
"answer_without_mutation",
|
|
102
|
+
true,
|
|
103
|
+
"The prompt envelope classifies this as advisory or planning-only work.",
|
|
104
|
+
"Answer without creating a task, journaling, editing files, committing, pushing, or creating a merge request.",
|
|
105
|
+
)
|
|
92
106
|
} else if prompt_intent == IntentKind::StatusQuestion {
|
|
93
107
|
(
|
|
94
108
|
"answer_status_only",
|
|
@@ -113,11 +127,20 @@ fn reason_codes(
|
|
|
113
127
|
prompt_intent: IntentKind,
|
|
114
128
|
) -> Vec<String> {
|
|
115
129
|
let mut codes = vec![format!("repo_state:{}", decision.state)];
|
|
130
|
+
if canonical.has_routing_envelope {
|
|
131
|
+
codes.push("prompt_has_routing_envelope".to_string());
|
|
132
|
+
}
|
|
133
|
+
codes.extend(canonical.validation_errors.iter().cloned());
|
|
116
134
|
if canonical.references_current_task {
|
|
117
135
|
codes.push("prompt_references_current_task".to_string());
|
|
118
136
|
}
|
|
119
137
|
for (kind, code) in [
|
|
120
138
|
(IntentKind::NewTask, "prompt_requests_new_goal"),
|
|
139
|
+
(
|
|
140
|
+
IntentKind::PromptNormalizationRequired,
|
|
141
|
+
"prompt_requires_normalization_envelope",
|
|
142
|
+
),
|
|
143
|
+
(IntentKind::Advisory, "prompt_requests_advisory_answer"),
|
|
121
144
|
(IntentKind::TaskRevision, "prompt_requests_correction"),
|
|
122
145
|
(IntentKind::CommitRequest, "prompt_requests_commit"),
|
|
123
146
|
(IntentKind::NoCommitRequest, "prompt_blocks_commit"),
|
|
@@ -153,6 +176,8 @@ fn certainty(intent: IntentKind, policy_action: &str, risk_codes: &[String]) ->
|
|
|
153
176
|
| IntentKind::RepairRequest
|
|
154
177
|
| IntentKind::NoCommitRequest
|
|
155
178
|
| IntentKind::CancelRequest
|
|
179
|
+
| IntentKind::PromptNormalizationRequired
|
|
180
|
+
| IntentKind::Advisory
|
|
156
181
|
) {
|
|
157
182
|
"exact"
|
|
158
183
|
} else {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
use super::model::{PromptSegment, RiskContext, SegmentKind};
|
|
2
|
-
use super::patterns::lexical_tokens;
|
|
3
2
|
|
|
4
3
|
pub(crate) fn detect_risk(segments: &[PromptSegment]) -> RiskContext {
|
|
5
4
|
let mut codes = Vec::new();
|
|
@@ -38,3 +37,14 @@ fn is_publish_command(tokens: &[String]) -> bool {
|
|
|
38
37
|
.windows(2)
|
|
39
38
|
.any(|window| window[0] == "npm" && window[1] == "publish")
|
|
40
39
|
}
|
|
40
|
+
|
|
41
|
+
fn lexical_tokens(text: &str) -> Vec<String> {
|
|
42
|
+
text.split_whitespace()
|
|
43
|
+
.map(|token| {
|
|
44
|
+
token
|
|
45
|
+
.trim_matches(|ch: char| !ch.is_alphanumeric() && ch != '_' && ch != '-')
|
|
46
|
+
.to_lowercase()
|
|
47
|
+
})
|
|
48
|
+
.filter(|token| !token.is_empty())
|
|
49
|
+
.collect()
|
|
50
|
+
}
|
|
@@ -3,7 +3,6 @@ mod envelope;
|
|
|
3
3
|
mod legacy;
|
|
4
4
|
mod legacy_response;
|
|
5
5
|
mod model;
|
|
6
|
-
mod patterns;
|
|
7
6
|
mod resolver;
|
|
8
7
|
mod resolver_active;
|
|
9
8
|
mod resolver_baseline;
|
|
@@ -23,6 +22,7 @@ use crate::task_state::{
|
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
use classifier::canonical_intent;
|
|
25
|
+
pub(crate) use envelope::prompt_envelope_json;
|
|
26
26
|
pub use legacy::{format_intent, IntentDecision, PromptEvidence};
|
|
27
27
|
use resolver::{resolve_intent, CompletedTaskReadiness, DirtyDiffReadiness};
|
|
28
28
|
|
|
@@ -57,6 +57,8 @@ pub(super) fn winning_rule(intent: &IntentDecision) -> String {
|
|
|
57
57
|
"current_task_revision_continues_task"
|
|
58
58
|
}
|
|
59
59
|
"answer_status_only" => "status_request_read_only",
|
|
60
|
+
"normalize_prompt_first" => "prompt_envelope_required_before_routing",
|
|
61
|
+
"answer_without_mutation" => "advisory_prompt_read_only",
|
|
60
62
|
"create_new_task" | "create_new_task_without_auto_baseline" => "ready_repo_new_task",
|
|
61
63
|
"create_isolated_task_worktree" => "dirty_repo_new_task_worktree_isolation",
|
|
62
64
|
"commit_user_diff_with_quality_gate" => "explicit_user_diff_commit_quality_gate",
|
|
@@ -164,6 +166,12 @@ pub(super) fn required_context_for_intent(intent: &IntentDecision) -> Vec<String
|
|
|
164
166
|
"answer_status_only" => {
|
|
165
167
|
push_unique(&mut context, "docs/naome/index.md");
|
|
166
168
|
}
|
|
169
|
+
"normalize_prompt_first" => {
|
|
170
|
+
push_unique(&mut context, "docs/naome/agent-workflow.md");
|
|
171
|
+
}
|
|
172
|
+
"answer_without_mutation" => {
|
|
173
|
+
push_unique(&mut context, "docs/naome/index.md");
|
|
174
|
+
}
|
|
167
175
|
"repair_harness_only" => {
|
|
168
176
|
push_unique(&mut context, ".naome/manifest.json");
|
|
169
177
|
push_unique(&mut context, "docs/naome/index.md");
|
|
@@ -66,6 +66,91 @@ fn prompt_context_uses_file_mentions_without_broad_markdown_context() {
|
|
|
66
66
|
.any(|item| item.path == "docs/naome/repository-quality.md"));
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
#[test]
|
|
70
|
+
fn prompt_context_ignores_nonexistent_concept_tokens_that_look_path_like() {
|
|
71
|
+
let repo = context_repo("context-prompt-concept-terms");
|
|
72
|
+
repo.write_file("docs/naome/repository-quality.md", "# Quality\n");
|
|
73
|
+
repo.commit_all("baseline");
|
|
74
|
+
|
|
75
|
+
let selection = select_context_for_prompt(
|
|
76
|
+
repo.path(),
|
|
77
|
+
"Advisory/planning-only prompts and German/English examples must not become paths.",
|
|
78
|
+
)
|
|
79
|
+
.unwrap();
|
|
80
|
+
|
|
81
|
+
assert_eq!(selection.mode, "prompt");
|
|
82
|
+
assert_eq!(
|
|
83
|
+
selection.required_context[0].path,
|
|
84
|
+
".naome/verification.json"
|
|
85
|
+
);
|
|
86
|
+
assert!(!selection
|
|
87
|
+
.required_context
|
|
88
|
+
.iter()
|
|
89
|
+
.any(|item| item.path == "Advisory/planning-only" || item.path == "German/English"));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[test]
|
|
93
|
+
fn prompt_context_prefers_envelope_referenced_paths_over_raw_prompt_tokens() {
|
|
94
|
+
let repo = context_repo("context-prompt-envelope-paths");
|
|
95
|
+
repo.write_file("packages/app/src/lib.rs", "pub fn app() {}\n");
|
|
96
|
+
repo.write_file("packages/app/src/other.rs", "pub fn other() {}\n");
|
|
97
|
+
repo.commit_all("baseline");
|
|
98
|
+
|
|
99
|
+
let selection = select_context_for_prompt(
|
|
100
|
+
repo.path(),
|
|
101
|
+
"```naome-prompt-envelope-v1\n{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"implementation\",\"mutationIntent\":\"modify_files\",\"workflowAction\":\"none\",\"taskIntent\":\"new_task\",\"risk\":\"none\",\"requestedActions\":[],\"referencedPaths\":[\"packages/app/src/lib.rs\"],\"constraints\":[],\"uncertainties\":[]}\n```\n\nPlease mention packages/app/src/other.rs in prose but use the envelope path.",
|
|
102
|
+
)
|
|
103
|
+
.unwrap();
|
|
104
|
+
|
|
105
|
+
assert_eq!(selection.mode, "prompt");
|
|
106
|
+
assert_eq!(
|
|
107
|
+
selection.required_context[0].path,
|
|
108
|
+
"packages/app/src/lib.rs"
|
|
109
|
+
);
|
|
110
|
+
assert!(!selection
|
|
111
|
+
.required_context
|
|
112
|
+
.iter()
|
|
113
|
+
.any(|item| item.path == "packages/app/src/other.rs"));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#[test]
|
|
117
|
+
fn prompt_context_keeps_envelope_paths_for_nested_creation_targets() {
|
|
118
|
+
let repo = app_context_repo("context-prompt-envelope-new-paths");
|
|
119
|
+
|
|
120
|
+
let selection = select_context_for_prompt(
|
|
121
|
+
repo.path(),
|
|
122
|
+
"```naome-prompt-envelope-v1\n{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"implementation\",\"mutationIntent\":\"create_files\",\"workflowAction\":\"none\",\"taskIntent\":\"new_task\",\"risk\":\"none\",\"requestedActions\":[],\"referencedPaths\":[\"packages/app/src/new/mod.rs\"],\"constraints\":[],\"uncertainties\":[]}\n```\n\nCreate the new module.",
|
|
123
|
+
)
|
|
124
|
+
.unwrap();
|
|
125
|
+
|
|
126
|
+
assert_eq!(selection.mode, "prompt");
|
|
127
|
+
assert_eq!(
|
|
128
|
+
selection.required_context[0].path,
|
|
129
|
+
"packages/app/src/new/mod.rs"
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#[test]
|
|
134
|
+
fn prompt_context_rejects_envelope_paths_outside_repository() {
|
|
135
|
+
let repo = app_context_repo("context-prompt-envelope-safe-paths");
|
|
136
|
+
|
|
137
|
+
let selection = select_context_for_prompt(
|
|
138
|
+
repo.path(),
|
|
139
|
+
"```naome-prompt-envelope-v1\n{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"implementation\",\"mutationIntent\":\"modify_files\",\"workflowAction\":\"none\",\"taskIntent\":\"new_task\",\"risk\":\"none\",\"requestedActions\":[],\"referencedPaths\":[\"../notes.md\",\"/tmp/file.rs\",\"packages/app/src/lib.rs\"],\"constraints\":[],\"uncertainties\":[]}\n```",
|
|
140
|
+
)
|
|
141
|
+
.unwrap();
|
|
142
|
+
|
|
143
|
+
assert_eq!(selection.mode, "prompt");
|
|
144
|
+
assert_eq!(
|
|
145
|
+
selection.required_context[0].path,
|
|
146
|
+
"packages/app/src/lib.rs"
|
|
147
|
+
);
|
|
148
|
+
assert!(!selection
|
|
149
|
+
.required_context
|
|
150
|
+
.iter()
|
|
151
|
+
.any(|item| item.path == "../notes.md" || item.path == "/tmp/file.rs"));
|
|
152
|
+
}
|
|
153
|
+
|
|
69
154
|
#[test]
|
|
70
155
|
fn context_selection_reports_over_budget_when_many_paths_change() {
|
|
71
156
|
let repo = context_repo("context-budget");
|
|
@@ -97,3 +182,10 @@ fn context_repo(name: &str) -> TestRepo {
|
|
|
97
182
|
);
|
|
98
183
|
repo
|
|
99
184
|
}
|
|
185
|
+
|
|
186
|
+
fn app_context_repo(name: &str) -> TestRepo {
|
|
187
|
+
let repo = context_repo(name);
|
|
188
|
+
repo.write_file("packages/app/src/lib.rs", "pub fn app() {}\n");
|
|
189
|
+
repo.commit_all("baseline");
|
|
190
|
+
repo
|
|
191
|
+
}
|
|
@@ -2,13 +2,20 @@ mod intent_support;
|
|
|
2
2
|
|
|
3
3
|
use naome_core::IntentDecision;
|
|
4
4
|
|
|
5
|
-
use intent_support::{completed_state,
|
|
5
|
+
use intent_support::{completed_state, idle, prompt_env, prompt_env_with_actions, Repo};
|
|
6
6
|
|
|
7
7
|
#[test]
|
|
8
8
|
fn repo_state_and_envelope_resolve_task_policy() {
|
|
9
9
|
let clean = Repo::clean("clean", idle());
|
|
10
10
|
assert_intent(
|
|
11
|
-
&clean.intent(
|
|
11
|
+
&clean.intent(&prompt_env(
|
|
12
|
+
"Please implement a small new feature.",
|
|
13
|
+
"implementation",
|
|
14
|
+
"modify_files",
|
|
15
|
+
"none",
|
|
16
|
+
"new_task",
|
|
17
|
+
"none",
|
|
18
|
+
)),
|
|
12
19
|
"ready_for_task",
|
|
13
20
|
"new_task",
|
|
14
21
|
"create_new_task",
|
|
@@ -18,7 +25,14 @@ fn repo_state_and_envelope_resolve_task_policy() {
|
|
|
18
25
|
let mut active_state = completed_state("HEAD", true);
|
|
19
26
|
active_state["status"] = serde_json::json!("implementing");
|
|
20
27
|
let active = Repo::clean("active", active_state);
|
|
21
|
-
let revision = active.intent(&
|
|
28
|
+
let revision = active.intent(&prompt_env(
|
|
29
|
+
"follow up",
|
|
30
|
+
"revision",
|
|
31
|
+
"modify_files",
|
|
32
|
+
"none",
|
|
33
|
+
"task_revision",
|
|
34
|
+
"none",
|
|
35
|
+
));
|
|
22
36
|
assert_intent(
|
|
23
37
|
&revision,
|
|
24
38
|
"active_task_in_progress",
|
|
@@ -26,7 +40,14 @@ fn repo_state_and_envelope_resolve_task_policy() {
|
|
|
26
40
|
"continue_current_task",
|
|
27
41
|
true,
|
|
28
42
|
);
|
|
29
|
-
let distinct = active.intent(&
|
|
43
|
+
let distinct = active.intent(&prompt_env(
|
|
44
|
+
"separate work",
|
|
45
|
+
"implementation",
|
|
46
|
+
"modify_files",
|
|
47
|
+
"none",
|
|
48
|
+
"new_task",
|
|
49
|
+
"none",
|
|
50
|
+
));
|
|
30
51
|
assert_intent(
|
|
31
52
|
&distinct,
|
|
32
53
|
"active_task_in_progress",
|
|
@@ -36,7 +57,14 @@ fn repo_state_and_envelope_resolve_task_policy() {
|
|
|
36
57
|
);
|
|
37
58
|
|
|
38
59
|
let completed = Repo::completed("completed", true);
|
|
39
|
-
let next = completed.intent(
|
|
60
|
+
let next = completed.intent(&prompt_env(
|
|
61
|
+
"After that, please implement a new task.",
|
|
62
|
+
"implementation",
|
|
63
|
+
"modify_files",
|
|
64
|
+
"none",
|
|
65
|
+
"new_task",
|
|
66
|
+
"none",
|
|
67
|
+
));
|
|
40
68
|
assert_intent(
|
|
41
69
|
&next,
|
|
42
70
|
"completed_task_unbaselined",
|
|
@@ -46,25 +74,55 @@ fn repo_state_and_envelope_resolve_task_policy() {
|
|
|
46
74
|
);
|
|
47
75
|
assert_eq!(
|
|
48
76
|
completed
|
|
49
|
-
.intent(&
|
|
77
|
+
.intent(&prompt_env_with_actions(
|
|
78
|
+
"review",
|
|
79
|
+
"implementation",
|
|
80
|
+
"none",
|
|
81
|
+
"review_request",
|
|
82
|
+
"none",
|
|
83
|
+
"none",
|
|
84
|
+
&["review"],
|
|
85
|
+
))
|
|
50
86
|
.policy_action,
|
|
51
87
|
"review_task_diff"
|
|
52
88
|
);
|
|
53
89
|
assert_eq!(
|
|
54
90
|
completed
|
|
55
|
-
.intent(&
|
|
91
|
+
.intent(&prompt_env_with_actions(
|
|
92
|
+
"cancel",
|
|
93
|
+
"implementation",
|
|
94
|
+
"none",
|
|
95
|
+
"cancel_request",
|
|
96
|
+
"none",
|
|
97
|
+
"none",
|
|
98
|
+
&["cancel"],
|
|
99
|
+
))
|
|
56
100
|
.policy_action,
|
|
57
101
|
"cancel_task_changes"
|
|
58
102
|
);
|
|
59
103
|
assert_eq!(
|
|
60
104
|
completed
|
|
61
|
-
.intent(&
|
|
105
|
+
.intent(&prompt_env(
|
|
106
|
+
"no commit",
|
|
107
|
+
"implementation",
|
|
108
|
+
"none",
|
|
109
|
+
"no_commit_request",
|
|
110
|
+
"new_task",
|
|
111
|
+
"none",
|
|
112
|
+
))
|
|
62
113
|
.policy_action,
|
|
63
114
|
"block_auto_baseline_due_to_no_commit"
|
|
64
115
|
);
|
|
65
116
|
assert_eq!(
|
|
66
117
|
completed
|
|
67
|
-
.intent(&
|
|
118
|
+
.intent(&prompt_env(
|
|
119
|
+
"revise",
|
|
120
|
+
"revision",
|
|
121
|
+
"modify_files",
|
|
122
|
+
"none",
|
|
123
|
+
"task_revision",
|
|
124
|
+
"none",
|
|
125
|
+
))
|
|
68
126
|
.policy_action,
|
|
69
127
|
"reopen_completed_task_revision"
|
|
70
128
|
);
|
|
@@ -72,8 +130,14 @@ fn repo_state_and_envelope_resolve_task_policy() {
|
|
|
72
130
|
|
|
73
131
|
#[test]
|
|
74
132
|
fn workflow_and_risk_intents_are_structured_not_language_keywords() {
|
|
75
|
-
let status =
|
|
76
|
-
|
|
133
|
+
let status = Repo::clean("status", idle()).intent(&prompt_env(
|
|
134
|
+
"anything",
|
|
135
|
+
"status",
|
|
136
|
+
"none",
|
|
137
|
+
"status_question",
|
|
138
|
+
"none",
|
|
139
|
+
"none",
|
|
140
|
+
));
|
|
77
141
|
assert_intent(
|
|
78
142
|
&status,
|
|
79
143
|
"ready_for_task",
|
|
@@ -84,7 +148,14 @@ fn workflow_and_risk_intents_are_structured_not_language_keywords() {
|
|
|
84
148
|
|
|
85
149
|
let dirty = Repo::clean("dirty", idle());
|
|
86
150
|
dirty.write("README.md", "# Manual edit\n");
|
|
87
|
-
let commit = dirty.intent(&
|
|
151
|
+
let commit = dirty.intent(&prompt_env(
|
|
152
|
+
"okay commit it",
|
|
153
|
+
"implementation",
|
|
154
|
+
"commit",
|
|
155
|
+
"commit_request",
|
|
156
|
+
"none",
|
|
157
|
+
"none",
|
|
158
|
+
));
|
|
88
159
|
assert_intent(
|
|
89
160
|
&commit,
|
|
90
161
|
"dirty_unowned_diff",
|
|
@@ -97,15 +168,17 @@ fn workflow_and_risk_intents_are_structured_not_language_keywords() {
|
|
|
97
168
|
assert_intent(
|
|
98
169
|
&deprecated,
|
|
99
170
|
"dirty_unowned_diff",
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
|
|
171
|
+
"prompt_normalization_required",
|
|
172
|
+
"normalize_prompt_first",
|
|
173
|
+
true,
|
|
103
174
|
);
|
|
104
175
|
|
|
105
|
-
let risky = Repo::clean("risky", idle()).intent(&
|
|
176
|
+
let risky = Repo::clean("risky", idle()).intent(&prompt_env(
|
|
106
177
|
"include this API key",
|
|
178
|
+
"implementation",
|
|
179
|
+
"commit",
|
|
107
180
|
"commit_request",
|
|
108
|
-
"
|
|
181
|
+
"none",
|
|
109
182
|
"credential_context",
|
|
110
183
|
));
|
|
111
184
|
assert_eq!(risky.prompt_intent, "unsafe");
|
|
@@ -116,7 +189,14 @@ fn workflow_and_risk_intents_are_structured_not_language_keywords() {
|
|
|
116
189
|
#[test]
|
|
117
190
|
fn invalid_completed_task_proof_blocks_new_task_baseline() {
|
|
118
191
|
let repo = Repo::completed("invalid", false);
|
|
119
|
-
let intent = repo.intent(
|
|
192
|
+
let intent = repo.intent(&prompt_env(
|
|
193
|
+
"After that, please implement a new task.",
|
|
194
|
+
"implementation",
|
|
195
|
+
"modify_files",
|
|
196
|
+
"none",
|
|
197
|
+
"new_task",
|
|
198
|
+
"none",
|
|
199
|
+
));
|
|
120
200
|
assert_eq!(intent.policy_action, "block_unsafe_intent");
|
|
121
201
|
assert!(intent
|
|
122
202
|
.risk_codes
|
|
@@ -11,12 +11,50 @@ use serde_json::{json, Value};
|
|
|
11
11
|
|
|
12
12
|
static REPO_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
13
13
|
|
|
14
|
-
pub fn
|
|
14
|
+
pub fn legacy_env(prompt: &str, workflow: &str, task: &str, risk: &str) -> String {
|
|
15
15
|
format!(
|
|
16
16
|
"```naome-intent-v2\n{{\"schema\":\"naome.intent.v2\",\"workflowAction\":\"{workflow}\",\"taskIntent\":\"{task}\",\"risk\":\"{risk}\"}}\n```\n\n{prompt}"
|
|
17
17
|
)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
pub fn prompt_env(
|
|
21
|
+
prompt: &str,
|
|
22
|
+
request_kind: &str,
|
|
23
|
+
mutation_intent: &str,
|
|
24
|
+
workflow: &str,
|
|
25
|
+
task: &str,
|
|
26
|
+
risk: &str,
|
|
27
|
+
) -> String {
|
|
28
|
+
prompt_env_with_actions(
|
|
29
|
+
prompt,
|
|
30
|
+
request_kind,
|
|
31
|
+
mutation_intent,
|
|
32
|
+
workflow,
|
|
33
|
+
task,
|
|
34
|
+
risk,
|
|
35
|
+
&[],
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
pub fn prompt_env_with_actions(
|
|
40
|
+
prompt: &str,
|
|
41
|
+
request_kind: &str,
|
|
42
|
+
mutation_intent: &str,
|
|
43
|
+
workflow: &str,
|
|
44
|
+
task: &str,
|
|
45
|
+
risk: &str,
|
|
46
|
+
actions: &[&str],
|
|
47
|
+
) -> String {
|
|
48
|
+
let requested_actions = actions
|
|
49
|
+
.iter()
|
|
50
|
+
.map(|action| format!("\"{action}\""))
|
|
51
|
+
.collect::<Vec<_>>()
|
|
52
|
+
.join(",");
|
|
53
|
+
format!(
|
|
54
|
+
"```naome-prompt-envelope-v1\n{{\"schema\":\"naome.prompt-envelope.v1\",\"requestKind\":\"{request_kind}\",\"mutationIntent\":\"{mutation_intent}\",\"workflowAction\":\"{workflow}\",\"taskIntent\":\"{task}\",\"risk\":\"{risk}\",\"requestedActions\":[{requested_actions}],\"referencedPaths\":[],\"constraints\":[],\"uncertainties\":[]}}\n```\n\n{prompt}"
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
20
58
|
pub fn idle() -> Value {
|
|
21
59
|
json!({ "status": "idle", "activeTask": null })
|
|
22
60
|
}
|