snow-flow 10.0.78 → 10.0.79
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/package.json +1 -1
- package/src/agent/agent.ts +13 -0
- package/src/agent/prompt/review.txt +30 -42
- package/src/session/index.ts +7 -0
- package/src/session/prompt/review-switch.txt +3 -2
- package/src/session/prompt.ts +32 -10
- package/src/tool/review.ts +14 -17
package/package.json
CHANGED
package/src/agent/agent.ts
CHANGED
|
@@ -132,6 +132,19 @@ export namespace Agent {
|
|
|
132
132
|
websearch: "allow",
|
|
133
133
|
codesearch: "allow",
|
|
134
134
|
review_exit: "allow",
|
|
135
|
+
external_directory: {
|
|
136
|
+
[path.join(Global.Path.data, "reviews", "*")]: "allow",
|
|
137
|
+
},
|
|
138
|
+
edit: {
|
|
139
|
+
"*": "deny",
|
|
140
|
+
[path.join(".snow-code", "reviews", "*.md")]: "allow",
|
|
141
|
+
[path.relative(Instance.worktree, path.join(Global.Path.data, path.join("reviews", "*.md")))]: "allow",
|
|
142
|
+
},
|
|
143
|
+
write: {
|
|
144
|
+
"*": "deny",
|
|
145
|
+
[path.join(".snow-code", "reviews", "*.md")]: "allow",
|
|
146
|
+
[path.relative(Instance.worktree, path.join(Global.Path.data, path.join("reviews", "*.md")))]: "allow",
|
|
147
|
+
},
|
|
135
148
|
}),
|
|
136
149
|
user,
|
|
137
150
|
),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
You are the Code Reuse Reviewer Agent for Snow-Flow. Your role is to analyze ServiceNow artifacts created or modified during development activities and identify opportunities for code reuse and standardization.
|
|
2
2
|
|
|
3
|
-
IMPORTANT: You are in READ-ONLY analysis mode. You cannot and should not modify any code.
|
|
3
|
+
IMPORTANT: You are in READ-ONLY analysis mode. You cannot and should not modify any code. The ONLY file you are allowed to write to is the review file (you will be told its path when entering review mode).
|
|
4
4
|
|
|
5
|
-
## Review
|
|
5
|
+
## Review Workflow
|
|
6
6
|
|
|
7
7
|
### Step 1: Gather Activity Context
|
|
8
8
|
- Read the activity details to understand what was created/modified
|
|
@@ -29,38 +29,32 @@ Look for these common reuse opportunities:
|
|
|
29
29
|
- Date/time utilities: Duration calculations, timezone handling
|
|
30
30
|
- User/group utilities: Role checks, assignment logic
|
|
31
31
|
|
|
32
|
-
### Step 5:
|
|
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
|
-
"approved": true | false,
|
|
61
|
-
"feedback": "If not approved, explanation for the developer"
|
|
62
|
-
}
|
|
63
|
-
```
|
|
32
|
+
### Step 5: Write Review Report
|
|
33
|
+
Write your findings to the review file. Structure as markdown with:
|
|
34
|
+
|
|
35
|
+
# Code Reuse Review
|
|
36
|
+
|
|
37
|
+
## Summary
|
|
38
|
+
Brief summary of findings and decision (approved / needs revision).
|
|
39
|
+
|
|
40
|
+
## Artifacts Reviewed
|
|
41
|
+
List of artifacts analyzed with type and name.
|
|
42
|
+
|
|
43
|
+
## Reuse Opportunities
|
|
44
|
+
For each finding:
|
|
45
|
+
- **Type**: existing_script_include / duplicate_pattern / refactor_suggestion
|
|
46
|
+
- **Severity**: high / medium / low
|
|
47
|
+
- **Description**: What was found
|
|
48
|
+
- **Existing Artifact**: Name and sys_id of existing Script Include (if applicable)
|
|
49
|
+
- **Recommendation**: Specific action to take
|
|
50
|
+
- **Code Location**: Where in the new code this applies
|
|
51
|
+
|
|
52
|
+
## Decision
|
|
53
|
+
- **Approved**: yes / no
|
|
54
|
+
- **Feedback**: If not approved, detailed explanation for the developer
|
|
55
|
+
|
|
56
|
+
### Step 6: Call review_exit
|
|
57
|
+
Once you have written your complete review to the review file, call `review_exit` to switch back to the build agent. The build agent will read your review file and act on the feedback.
|
|
64
58
|
|
|
65
59
|
## Decision Criteria
|
|
66
60
|
|
|
@@ -85,15 +79,9 @@ Structure your findings as JSON:
|
|
|
85
79
|
|
|
86
80
|
## Important Guidelines
|
|
87
81
|
|
|
88
|
-
1. READ-ONLY: You cannot modify any code.
|
|
82
|
+
1. READ-ONLY: You cannot modify any code. Only the review file can be written to.
|
|
89
83
|
2. ES5 Awareness: ServiceNow uses ES5. If you see ES6+ syntax, flag it as a concern.
|
|
90
84
|
3. Be Constructive: When requesting revision, provide specific, actionable feedback with examples.
|
|
91
85
|
4. Consider Context: Not all code needs to be in Script Includes. Consider frequency of reuse, complexity, and scope.
|
|
92
86
|
5. Document Reasoning: Always explain WHY you made your decision, not just WHAT you decided.
|
|
93
|
-
|
|
94
|
-
## Completing Your Review
|
|
95
|
-
|
|
96
|
-
After completing your review, call `review_exit` with your JSON review report.
|
|
97
|
-
|
|
98
|
-
- If APPROVED: Include any low-severity suggestions as informational notes in the report.
|
|
99
|
-
- If NEEDS REVISION: Provide detailed feedback explaining what needs to change. The build agent will address the feedback.
|
|
87
|
+
6. Your turn should only end with calling review_exit. Do not stop without calling it.
|
package/src/session/index.ts
CHANGED
|
@@ -242,6 +242,13 @@ export namespace Session {
|
|
|
242
242
|
return path.join(base, [input.time.created, input.slug].join("-") + ".md")
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
export function review(input: { slug: string; time: { created: number } }) {
|
|
246
|
+
const base = Instance.project.vcs
|
|
247
|
+
? path.join(Instance.worktree, ".snow-code", "reviews")
|
|
248
|
+
: path.join(Global.Path.data, "reviews")
|
|
249
|
+
return path.join(base, [input.time.created, input.slug].join("-") + ".md")
|
|
250
|
+
}
|
|
251
|
+
|
|
245
252
|
export const get = fn(Identifier.schema("session"), async (id) => {
|
|
246
253
|
const read = await Storage.read<Info>(["session", Instance.project.id, id])
|
|
247
254
|
return read as Info
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<system-reminder>
|
|
2
2
|
Your operational mode has changed from review to build.
|
|
3
3
|
You are no longer in read-only analysis mode.
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
You are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed.
|
|
5
|
+
The code review results have been provided in the review file. Read it and act on the review feedback.
|
|
6
|
+
If approved, proceed with activity_complete. If revision needed, address the feedback first.
|
|
6
7
|
</system-reminder>
|
package/src/session/prompt.ts
CHANGED
|
@@ -1333,27 +1333,49 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
1333
1333
|
|
|
1334
1334
|
// Switching from review to build
|
|
1335
1335
|
if (input.agent.name === "build" && assistantMessage?.info.agent === "review") {
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1336
|
+
const reviewPath = Session.review(input.session)
|
|
1337
|
+
const reviewExists = await Bun.file(reviewPath).exists()
|
|
1338
|
+
if (reviewExists) {
|
|
1339
|
+
const part = await Session.updatePart({
|
|
1340
|
+
id: Identifier.ascending("part"),
|
|
1341
|
+
messageID: userMessage.info.id,
|
|
1342
|
+
sessionID: userMessage.info.sessionID,
|
|
1343
|
+
type: "text",
|
|
1344
|
+
text:
|
|
1345
|
+
REVIEW_SWITCH +
|
|
1346
|
+
"\n\n" +
|
|
1347
|
+
`A review file exists at ${reviewPath}. You should read it and act on the review feedback within it`,
|
|
1348
|
+
synthetic: true,
|
|
1349
|
+
})
|
|
1350
|
+
clonedUser.parts.push(part)
|
|
1351
|
+
}
|
|
1344
1352
|
return replaceUser()
|
|
1345
1353
|
}
|
|
1346
1354
|
|
|
1347
1355
|
// Entering review mode
|
|
1348
1356
|
if (input.agent.name === "review" && assistantMessage?.info.agent !== "review") {
|
|
1349
|
-
|
|
1357
|
+
const reviewPath = Session.review(input.session)
|
|
1358
|
+
const reviewExists = await Bun.file(reviewPath).exists()
|
|
1359
|
+
if (!reviewExists) await fs.mkdir(path.dirname(reviewPath), { recursive: true })
|
|
1360
|
+
const part = await Session.updatePart({
|
|
1350
1361
|
id: Identifier.ascending("part"),
|
|
1351
1362
|
messageID: userMessage.info.id,
|
|
1352
1363
|
sessionID: userMessage.info.sessionID,
|
|
1353
1364
|
type: "text",
|
|
1354
|
-
text: `<system-reminder
|
|
1365
|
+
text: `<system-reminder>
|
|
1366
|
+
Review mode is active. You are in READ-ONLY analysis mode (except for the review file).
|
|
1367
|
+
Your role is to analyze ServiceNow artifacts for code reuse opportunities.
|
|
1368
|
+
Use snow_analyze_artifact, snow_find_artifact, snow_comprehensive_search, and snow_query_table.
|
|
1369
|
+
|
|
1370
|
+
## Review File Info:
|
|
1371
|
+
${reviewExists ? `A review file already exists at ${reviewPath}. You can read it and make incremental edits using the edit tool.` : `No review file exists yet. You should create your review at ${reviewPath} using the write tool.`}
|
|
1372
|
+
Write your review findings to this file. NOTE that this is the only file you are allowed to edit.
|
|
1373
|
+
|
|
1374
|
+
When your review is complete, call review_exit to switch back to the build agent.
|
|
1375
|
+
</system-reminder>`,
|
|
1355
1376
|
synthetic: true,
|
|
1356
1377
|
})
|
|
1378
|
+
clonedUser.parts.push(part)
|
|
1357
1379
|
return replaceUser()
|
|
1358
1380
|
}
|
|
1359
1381
|
|
package/src/tool/review.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import z from "zod"
|
|
2
|
+
import path from "path"
|
|
2
3
|
import { Tool } from "./tool"
|
|
3
4
|
import { Question } from "../question"
|
|
4
5
|
import { Session } from "../session"
|
|
5
6
|
import { MessageV2 } from "../session/message-v2"
|
|
6
7
|
import { Identifier } from "../id/id"
|
|
7
8
|
import { Provider } from "../provider/provider"
|
|
9
|
+
import { Instance } from "../project/instance"
|
|
8
10
|
import EXIT_DESCRIPTION from "./review-exit.txt"
|
|
9
11
|
import ENTER_DESCRIPTION from "./review-enter.txt"
|
|
10
12
|
|
|
@@ -17,16 +19,15 @@ async function getLastModel(sessionID: string) {
|
|
|
17
19
|
|
|
18
20
|
export const ReviewExitTool = Tool.define("review_exit", {
|
|
19
21
|
description: EXIT_DESCRIPTION,
|
|
20
|
-
parameters: z.object({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
async execute(params, ctx) {
|
|
22
|
+
parameters: z.object({}),
|
|
23
|
+
async execute(_params, ctx) {
|
|
24
|
+
const session = await Session.get(ctx.sessionID)
|
|
25
|
+
const reviewFile = path.relative(Instance.worktree, Session.review(session))
|
|
25
26
|
const answers = await Question.ask({
|
|
26
27
|
sessionID: ctx.sessionID,
|
|
27
28
|
questions: [
|
|
28
29
|
{
|
|
29
|
-
question: `
|
|
30
|
+
question: `Review at ${reviewFile} is complete. Would you like to switch to the build agent and start acting on the feedback?`,
|
|
30
31
|
header: "Build Agent",
|
|
31
32
|
custom: false,
|
|
32
33
|
options: [
|
|
@@ -54,20 +55,12 @@ export const ReviewExitTool = Tool.define("review_exit", {
|
|
|
54
55
|
model,
|
|
55
56
|
}
|
|
56
57
|
await Session.updateMessage(userMsg)
|
|
57
|
-
|
|
58
|
-
const reviewSummary = params.reviewResult
|
|
59
|
-
? `\n\nReview result:\n${params.reviewResult}`
|
|
60
|
-
: ""
|
|
61
|
-
const approvalStatus = params.approved !== undefined
|
|
62
|
-
? `\nApproved: ${params.approved}`
|
|
63
|
-
: ""
|
|
64
|
-
|
|
65
58
|
await Session.updatePart({
|
|
66
59
|
id: Identifier.ascending("part"),
|
|
67
60
|
messageID: userMsg.id,
|
|
68
61
|
sessionID: ctx.sessionID,
|
|
69
62
|
type: "text",
|
|
70
|
-
text: `The
|
|
63
|
+
text: `The review at ${reviewFile} has been approved, you can now edit files. Act on the review feedback`,
|
|
71
64
|
synthetic: true,
|
|
72
65
|
} satisfies MessageV2.TextPart)
|
|
73
66
|
|
|
@@ -87,11 +80,14 @@ export const ReviewEnterTool = Tool.define("review_enter", {
|
|
|
87
80
|
updateSetName: z.string().optional().describe("Name of the update set being reviewed"),
|
|
88
81
|
}),
|
|
89
82
|
async execute(params, ctx) {
|
|
83
|
+
const session = await Session.get(ctx.sessionID)
|
|
84
|
+
const reviewFile = path.relative(Instance.worktree, Session.review(session))
|
|
85
|
+
|
|
90
86
|
const answers = await Question.ask({
|
|
91
87
|
sessionID: ctx.sessionID,
|
|
92
88
|
questions: [
|
|
93
89
|
{
|
|
94
|
-
question: `Activity is ready for code reuse review. Would you like to switch to the review agent?`,
|
|
90
|
+
question: `Activity is ready for code reuse review. Would you like to switch to the review agent and save findings to ${reviewFile}?`,
|
|
95
91
|
header: "Review Mode",
|
|
96
92
|
custom: false,
|
|
97
93
|
options: [
|
|
@@ -122,6 +118,7 @@ export const ReviewEnterTool = Tool.define("review_enter", {
|
|
|
122
118
|
|
|
123
119
|
const context = [
|
|
124
120
|
"User has requested to enter review mode. Switch to review mode and begin code reuse analysis.",
|
|
121
|
+
`The review file will be at ${reviewFile}.`,
|
|
125
122
|
params.activityId ? `Activity ID: ${params.activityId}` : "",
|
|
126
123
|
params.updateSetName ? `Update Set: ${params.updateSetName}` : "",
|
|
127
124
|
params.artifacts ? `Artifacts to review:\n${params.artifacts}` : "",
|
|
@@ -140,7 +137,7 @@ export const ReviewEnterTool = Tool.define("review_enter", {
|
|
|
140
137
|
|
|
141
138
|
return {
|
|
142
139
|
title: "Switching to review agent",
|
|
143
|
-
output:
|
|
140
|
+
output: `User confirmed to switch to review mode. A new message has been created to switch you to review mode. The review file will be at ${reviewFile}. Begin code reuse analysis.`,
|
|
144
141
|
metadata: {},
|
|
145
142
|
}
|
|
146
143
|
},
|