Skip to content

Commit 02df216

Browse files
authored
Merge pull request #288 from neuroverse-fm/feat/standard-json-schema-spec
feat: standard json schema support
2 parents cc66240 + fb32604 commit 02df216

57 files changed

Lines changed: 1826 additions & 1513 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ Since v2.1.0, we're keeping a changelog of each version's changes in NeuroPilot.
66

77
Changes between each version before then will not be listed.
88

9+
## 3.0.0
10+
11+
### Additions
12+
13+
- Internally, NeuroPilot changed to use [Zod](https://zod.dev) for JSON schema generation and validation.
14+
- This shouldn't mean that schemas are changed (except `rewrite_lines`, which is intentional). If any schemas have been changed as a result of this, it is considered a regression, and [is worth reporting](https://github.com/VSC-NeuroPilot/neuropilot/issues/new).
15+
- NeuroPilot actually accepts any TypeScript schema library that conforms to the [Standard JSON Schema specification](https://standardschema.dev/json-schema), however this is only relevant for the public API where companion developers can choose between schema libraries listed as compatible in the above list.
16+
- By default, NeuroPilot will attempt to convert these schemas to the `draft-07` JSON schema version. Failing that, it will try to convert to `draft-2020-12` instead, with a warning logged in console. NeuroPilot does *not* attempt conversion to `openapi-3.0`, as it uses keywords not in the official JSON schema specification.
17+
918
## 2.5.0
1019

1120
### New settings

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ Please refer to our [contributor docs](https://vsc-neuropilot.github.io/docs/met
55
## Contributing
66

77
If you have an idea or want to contribute a feature, please first [create an issue](https://github.com/VSC-NeuroPilot/neuropilot/issues) or send a message to `@Pasu4` in the project's [post on the Neuro Discord](https://discord.com/channels/574720535888396288/1350968830230396938).
8-
If you make a pull request that contributes code, please run `npm run lint src` and resolve any errors that did not get auto-fixed, preferrably before each commit.
8+
If you make a pull request that contributes code, please run `pnpm run lint src` and resolve any errors that did not get auto-fixed, preferrably before each commit.
99

1010
PRs should generally target the `dev` branch (or another feature branch) unless there is a specific reason to do otherwise (if so, please explain it in your PR).
1111

12+
New actions should use [Zod](https://zod.dev) for schema generation, instead of plain JSON schema objects.
13+
1214
This repository accepts only TypeScript for the main code. Submissions in JavaScript to the core code will require a conversion to TypeScript first.
1315

1416
## Views

esbuild-configs/web.esbuild.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export async function webTestBrowser(_prodFlag, watchFlag) {
141141
polyfillNode({
142142
polyfills: {
143143
child_process: false,
144+
crypto: true,
144145
module: false,
145146
os: false,
146147
path: false,

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,8 @@
819819
"build:web:esbuild": "node ./scripts/esbuild.mjs --mode web",
820820
"build:desktop:tsc": "tsc --noEmit --project tsconfig.app.json",
821821
"build:desktop:esbuild": "node ./scripts/esbuild.mjs --mode desktop",
822+
"build:webview:tsc": "tsc --noEmit --project tsconfig.webview.json",
823+
"build:webview:esbuild": "node ./scripts/esbuild.mjs --mode webview",
822824
"watch:web": "npm-run-all -p watch:web:* watch:webview:*",
823825
"watch:desktop": "npm-run-all -p watch:desktop:* watch:webview:*",
824826
"watch:web:esbuild": "node ./scripts/esbuild.mjs --watch --mode web",
@@ -847,6 +849,7 @@
847849
},
848850
"devDependencies": {
849851
"@eslint/js": "^10.0.1",
852+
"@standard-schema/spec": "^1.1.0",
850853
"@stylistic/eslint-plugin": "^5.10.0",
851854
"@types/glob-to-regexp": "^0.4.4",
852855
"@types/json-schema": "^7.0.15",
@@ -886,6 +889,7 @@
886889
"ignore": "^7.0.5",
887890
"jsonschema": "^1.5.0",
888891
"neuro-game-sdk": "^1.1.1",
889-
"preact": "^10.29.2"
892+
"preact": "^10.29.2",
893+
"zod": "^4.4.3"
890894
}
891895
}

pnpm-lock.yaml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/changelog.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as vscode from 'vscode';
2+
import { z } from 'zod';
23

34
import { EXCEPTION_THROWN_STRING, NEURO } from '@/constants';
45
import { getFence, logOutput } from '@/utils/misc';
5-
import { actionHandlerFailure, ActionHandlerResult, actionHandlerSuccess, RCEAction } from '@/utils/neuro_client';
6+
import { actionHandlerFailure, ActionHandlerResult, actionHandlerSuccess, defineAction } from '@/utils/neuro_client';
67
import { CONNECTION, PermissionLevel } from '@/config';
78
import { addActions, CATEGORY_MISC } from './rce';
8-
import { RCEContext } from '@ctx/rce';
99

1010
const MEMENTO_KEY = 'lastDeliveredChangelogVersion';
1111

@@ -15,24 +15,22 @@ interface ChangelogSection {
1515
}
1616

1717
export const changelogActions = {
18-
read_changelog: {
18+
read_changelog: defineAction({
1919
name: 'read_changelog',
2020
description: 'Get changelog entries starting from a specified version. If fromVersion is omitted, any new entries after the last read_changelog command are read.',
2121
category: CATEGORY_MISC,
22-
schema: {
23-
type: 'object',
24-
properties: {
25-
fromVersion: { type: 'string', description: 'Version (e.g., 2.2.1) to start including entries from, inclusive.' },
26-
},
27-
additionalProperties: false,
28-
},
22+
schema: z.object({
23+
fromVersion: z.string().meta({
24+
description: 'Version (e.g., 2.2.1) to start including entries from, inclusive.',
25+
}),
26+
}),
2927
defaultPermission: PermissionLevel.COPILOT,
30-
handler: handleReadChangelog,
31-
promptGenerator: (context: RCEContext) => context.data.params?.fromVersion
28+
handler: (ctx) => handleReadChangelog(ctx.data.params.fromVersion),
29+
promptGenerator: (context) => context.data.params.fromVersion
3230
? `read all changelog entries starting from version ${context.data.params.fromVersion} (inclusive).`
3331
: 'read the latest changelog entries.',
34-
},
35-
} satisfies Record<string, RCEAction>;
32+
}),
33+
};
3634

3735
export function addChangelogActions(): void {
3836
addActions([changelogActions.read_changelog]);
@@ -84,8 +82,8 @@ export async function sendChangelogOnDemand() {
8482
}
8583
}
8684

87-
function handleReadChangelog(context: RCEContext): Thenable<ActionHandlerResult> {
88-
return readAndStructureChangelog(context.data.params?.fromVersion);
85+
function handleReadChangelog(version: string): Thenable<ActionHandlerResult> {
86+
return readAndStructureChangelog(version);
8987
}
9088

9189
async function readAndParseChangelog(): Promise<{ sections: ChangelogSection[]; latest: string; }> {

src/chat.ts

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import * as vscode from 'vscode';
2+
import assert from 'node:assert';
3+
import { z } from 'zod';
24

35
import { NEURO } from '@/constants';
46
import { filterFileContents, logOutput, simpleFileName } from '@/utils/misc';
57
import { CONFIG, CONNECTION, PermissionLevel } from '@/config';
6-
import assert from 'node:assert';
7-
import { JSONSchema7 } from 'json-schema';
8-
import { actionHandlerFailure, actionHandlerSuccess, actionValidationAccept, actionValidationFailure, RCEAction, RCEHandlerReturns } from './utils/neuro_client';
9-
import { RCEContext } from './context/rce';
8+
import { actionHandlerFailure, actionHandlerSuccess, actionValidationAccept, actionValidationFailure, defineAction } from './utils/neuro_client';
109
import { abortActionForce, addActions, registerAction, tryForceActions } from '@/rce';
1110

1211
let requestCancelled = false;
@@ -49,35 +48,28 @@ export function addChatAction() {
4948
addActions([chatAction], false);
5049
}
5150

52-
function handleChat(context: RCEContext): RCEHandlerReturns {
53-
const answer = context.data.params!.answer;
54-
55-
if (requestCancelled) {
56-
return actionHandlerFailure('Request was cancelled');
57-
}
58-
59-
lastChatResponse = answer;
60-
logOutput('INFO', 'Received chat response:\n' + answer);
61-
return actionHandlerSuccess();
62-
}
63-
64-
export const chatAction: RCEAction = {
51+
export const chatAction = defineAction({
6552
name: 'chat',
6653
description:
6754
`Provide an answer to ${CONNECTION.userName}'s request.` +
6855
' Use markdown to format your response.' +
6956
' You may additionally include code blocks by using triple backticks.' +
7057
' Be sure to use the correct language identifier after the first set of backticks.' +
7158
' If you decide to include a code block, make sure to explain what it is doing.',
72-
schema: {
73-
type: 'object',
74-
properties: {
75-
answer: { type: 'string' },
76-
},
77-
required: ['answer'],
78-
additionalProperties: false,
79-
} satisfies JSONSchema7,
80-
handler: handleChat,
59+
schema: z.object({
60+
answer: z.string(),
61+
}),
62+
handler(ctx) {
63+
const answer = ctx.data.params.answer;
64+
65+
if (requestCancelled) {
66+
return actionHandlerFailure('Request was cancelled');
67+
}
68+
69+
lastChatResponse = answer;
70+
logOutput('INFO', 'Received chat response:\n' + answer);
71+
return actionHandlerSuccess();
72+
},
8173
validators: {
8274
sync: [
8375
() => NEURO.currentActionForce // This is done before the action force is cleared
@@ -92,7 +84,7 @@ export const chatAction: RCEAction = {
9284
category: 'Chat',
9385
hidden: true,
9486
defaultPermission: PermissionLevel.OFF, // Used with overridePermissions in forceActions
95-
} as const;
87+
});
9688

9789
export function registerChatParticipant() {
9890
const handler: vscode.ChatRequestHandler = async (

src/completions.ts

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
import * as vscode from 'vscode';
2+
import { ActionForcePriorityEnum } from 'neuro-game-sdk';
3+
import { z } from 'zod';
4+
25
import { NEURO } from '@/constants';
36
import { logOutput, simpleFileName, getPositionContext, formatContext, NeuroPositionContext } from '@/utils/misc';
47
import { CONFIG, CONNECTION, PermissionLevel } from '@/config';
5-
import { JSONSchema7 } from 'json-schema';
6-
import { actionHandlerFailure, actionHandlerSuccess, actionValidationAccept, actionValidationFailure, actionValidationRetry, RCEAction, RCEHandlerReturns } from '@/utils/neuro_client';
7-
import { RCEContext } from '@ctx/rce';
8+
import { actionHandlerFailure, actionHandlerSuccess, actionValidationAccept, actionValidationFailure, actionValidationRetry, defineAction } from '@/utils/neuro_client';
89
import { abortActionForce, addActions, canForceActions, tryForceActions } from '@/rce';
9-
import { ActionForcePriorityEnum } from 'neuro-game-sdk';
1010

1111
let lastSuggestions: string[] = [];
1212
let requestCancelled = false;
1313

1414
// TODO: Figure out how to do this with maxCount
1515
// export const completionAction = (maxCount: number) => ({
16-
export const completeCodeAction: RCEAction = {
16+
export const completeCodeAction = defineAction({
1717
name: 'complete_code',
1818
description: 'Suggest code to write.' +
1919
' Only one suggestion you provide will be chosen.' +
2020
' Your suggestions can be single lines or multi-line code snippets.',
21-
schema: {
22-
type: 'object',
23-
properties: {
24-
suggestions: {
25-
type: 'array',
26-
items: { type: 'string' },
27-
maxItems: 3,
28-
},
29-
},
30-
required: ['suggestions'],
31-
additionalProperties: false,
32-
} satisfies JSONSchema7,
21+
schema: z.object({
22+
suggestions: z.array(z.string()).max(3),
23+
}),
3324
category: 'Completions',
34-
handler: handleCompleteCode,
25+
handler(ctx) {
26+
if (requestCancelled)
27+
return actionHandlerFailure('Request was cancelled');
28+
if (!NEURO.currentActionForce)
29+
return actionHandlerFailure('Not currently waiting for suggestions');
30+
31+
lastSuggestions = ctx.data.params.suggestions;
32+
logOutput('INFO', 'Received suggestions:\n' + JSON.stringify(lastSuggestions));
33+
return actionHandlerSuccess();
34+
},
3535
validators: {
3636
sync: [
3737
() => NEURO.currentActionForce // This is done before the action force is cleared
@@ -51,18 +51,7 @@ export const completeCodeAction: RCEAction = {
5151
promptGenerator: null, // Only ever run in Autopilot mode
5252
defaultPermission: PermissionLevel.OFF, // Used with overridePermissions in forceActions
5353
hidden: true,
54-
} as const;
55-
56-
function handleCompleteCode(context: RCEContext): RCEHandlerReturns {
57-
if (requestCancelled)
58-
return actionHandlerFailure('Request was cancelled');
59-
if (!NEURO.currentActionForce)
60-
return actionHandlerFailure('Not currently waiting for suggestions');
61-
62-
lastSuggestions = context.data.params.suggestions;
63-
logOutput('INFO', 'Received suggestions:\n' + JSON.stringify(lastSuggestions));
64-
return actionHandlerSuccess();
65-
}
54+
});
6655

6756
export function addCompleteCodeAction() {
6857
addActions([completeCodeAction], false);

src/config.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import * as vscode from 'vscode';
2+
23
import { NEURO } from '@/constants';
34
import { logOutput } from '@/utils/misc';
45
import { getAction } from '@/rce';
6+
import { PermissionLevel } from '@typing/actions';
7+
8+
export { PermissionLevel }; // re-exporting for the sake of compat I'm done with this
59

610
//#region Types
711

@@ -409,13 +413,6 @@ export async function checkDeprecatedSettings(version: string) {
409413
}
410414
}
411415

412-
/** Permission level enums */
413-
export const enum PermissionLevel {
414-
OFF = 0,
415-
COPILOT = 1,
416-
AUTOPILOT = 2,
417-
}
418-
419416
export function permissionLevelToString(level: PermissionLevel): string {
420417
switch (level) {
421418
case PermissionLevel.AUTOPILOT:

src/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as vscode from 'vscode';
2-
import { NeuroClient } from 'neuro-game-sdk';
2+
import { NeuroClient, type ActionData } from 'neuro-game-sdk';
3+
34
import { TerminalSession } from './pseudoterminal';
45
import type { GitExtension } from '@typing/git.d';
56
import { ActionsViewProvider } from '@views/actions';
67
import { ImagesViewProvider } from '@views/image';
78
import type { ExecuteViewProvider } from '@views/execute';
8-
import type { ActionData } from 'neuro-game-sdk';
99
import type { ActionForceParams } from './utils/neuro_client';
1010

1111
export interface NeuroTask {

0 commit comments

Comments
 (0)