veryfront 0.1.211 → 0.1.213

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.
Files changed (33) hide show
  1. package/esm/cli/mcp/advanced-tools.d.ts.map +1 -1
  2. package/esm/cli/mcp/advanced-tools.js +2 -0
  3. package/esm/cli/mcp/standalone.d.ts.map +1 -1
  4. package/esm/cli/mcp/standalone.js +39 -0
  5. package/esm/cli/mcp/tools/bootstrap-tool.d.ts +29 -0
  6. package/esm/cli/mcp/tools/bootstrap-tool.d.ts.map +1 -0
  7. package/esm/cli/mcp/tools/bootstrap-tool.js +51 -0
  8. package/esm/cli/mcp/tools/cicd-tools.d.ts +13 -0
  9. package/esm/cli/mcp/tools/cicd-tools.d.ts.map +1 -1
  10. package/esm/cli/mcp/tools/cicd-tools.js +14 -83
  11. package/esm/deno.js +1 -1
  12. package/esm/src/agent/data-stream.d.ts.map +1 -1
  13. package/esm/src/agent/data-stream.js +42 -3
  14. package/esm/src/agent/runtime/constants.d.ts +2 -0
  15. package/esm/src/agent/runtime/constants.d.ts.map +1 -1
  16. package/esm/src/agent/runtime/constants.js +16 -0
  17. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  18. package/esm/src/agent/runtime/index.js +7 -5
  19. package/esm/src/internal-agents/schema.d.ts.map +1 -1
  20. package/esm/src/internal-agents/schema.js +24 -1
  21. package/esm/src/utils/version-constant.d.ts +1 -1
  22. package/esm/src/utils/version-constant.js +1 -1
  23. package/package.json +1 -1
  24. package/src/cli/mcp/advanced-tools.ts +2 -0
  25. package/src/cli/mcp/standalone.ts +42 -0
  26. package/src/cli/mcp/tools/bootstrap-tool.ts +67 -0
  27. package/src/cli/mcp/tools/cicd-tools.ts +15 -92
  28. package/src/deno.js +1 -1
  29. package/src/src/agent/data-stream.ts +46 -3
  30. package/src/src/agent/runtime/constants.ts +18 -0
  31. package/src/src/agent/runtime/index.ts +7 -5
  32. package/src/src/internal-agents/schema.ts +28 -1
  33. package/src/src/utils/version-constant.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"advanced-tools.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/advanced-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA+B1C,eAAO,MAAM,aAAa,EAAE,OAAO,EAyBlC,CAAC"}
1
+ {"version":3,"file":"advanced-tools.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/advanced-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAgC1C,eAAO,MAAM,aAAa,EAAE,OAAO,EA0BlC,CAAC"}
@@ -6,11 +6,13 @@ import { vfRunLint } from "./tools/run-lint-tool.js";
6
6
  import { vfRunTests } from "./tools/run-tests-tool.js";
7
7
  import { vfGetConventions, vfScaffold } from "./tools/scaffold-tools.js";
8
8
  import { vfGetSkillReference, vfGetSkills } from "./tools/skill-tools.js";
9
+ import { vfBootstrap } from "./tools/bootstrap-tool.js";
9
10
  import { cicdTools } from "./tools/cicd-tools.js";
10
11
  import { introspectionTools } from "./tools/introspection-tools.js";
11
12
  export const advancedTools = [
12
13
  ...cicdTools,
13
14
  ...introspectionTools,
15
+ vfBootstrap,
14
16
  vfGetSkills,
15
17
  vfGetSkillReference,
16
18
  vfListLocalProjects,
@@ -1 +1 @@
1
- {"version":3,"file":"standalone.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/standalone.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAA4B;gBAEnC,MAAM,GAAE,mBAAwB;IAM5C,KAAK,IAAI,IAAI;IAWb,IAAI,IAAI,IAAI;YAME,aAAa;IAW3B,OAAO,CAAC,cAAc;YAgCR,eAAe;IAqB7B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,mBAAmB;YAyBb,mBAAmB;IA6CjC,OAAO,CAAC,iBAAiB;YAkBX,gBAAgB;IAwB9B,OAAO,CAAC,WAAW;IAwNnB,OAAO,CAAC,mBAAmB;CA0F5B;AAED,wBAAgB,yBAAyB,CAAC,MAAM,GAAE,mBAAwB,GAAG,mBAAmB,CAI/F"}
1
+ {"version":3,"file":"standalone.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/standalone.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAA4B;gBAEnC,MAAM,GAAE,mBAAwB;IAM5C,KAAK,IAAI,IAAI;IAWb,IAAI,IAAI,IAAI;YAME,aAAa;IAW3B,OAAO,CAAC,cAAc;YAgCR,eAAe;IAqB7B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,mBAAmB;YAyBb,mBAAmB;IA6CjC,OAAO,CAAC,iBAAiB;YAkBX,gBAAgB;IAwB9B,OAAO,CAAC,WAAW;IAkQnB,OAAO,CAAC,mBAAmB;CA0F5B;AAED,wBAAgB,yBAAyB,CAAC,MAAM,GAAE,mBAAwB,GAAG,mBAAmB,CAI/F"}
@@ -403,6 +403,45 @@ export class StandaloneMCPServer {
403
403
  });
404
404
  },
405
405
  },
406
+ {
407
+ name: "vf_bootstrap",
408
+ description: "Get full project context in one call: structure, conventions, errors, and server status. " +
409
+ "Use at session start instead of calling vf_get_project_context + vf_get_conventions + " +
410
+ "vf_get_errors + vf_get_status separately.",
411
+ inputSchema: {
412
+ type: "object",
413
+ properties: {
414
+ projectPath: {
415
+ type: "string",
416
+ description: "Project directory (defaults to cwd)",
417
+ },
418
+ },
419
+ },
420
+ async execute(args) {
421
+ const { vfGetProjectContext } = await import("./tools/project-tools.js");
422
+ const { vfGetConventions } = await import("./tools/scaffold-tools.js");
423
+ const [project, conventions] = await Promise.all([
424
+ vfGetProjectContext.execute({ projectPath: args.projectPath }),
425
+ vfGetConventions.execute({ topic: "all" }),
426
+ ]);
427
+ let errors = [];
428
+ let running = false;
429
+ try {
430
+ const result = await client.getLiveErrors();
431
+ errors = Array.isArray(result) ? result : [];
432
+ running = true;
433
+ }
434
+ catch {
435
+ // Dev server not running — no errors available
436
+ }
437
+ return {
438
+ project,
439
+ conventions,
440
+ errors: { total: errors.length, items: errors.slice(-20) },
441
+ status: { running },
442
+ };
443
+ },
444
+ },
406
445
  ...this.createContext7Tools(),
407
446
  ];
408
447
  }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * MCP tool: vf_bootstrap
3
+ *
4
+ * Returns everything an agent needs at session start in a single call:
5
+ * project context, coding conventions, current errors, and server status.
6
+ */
7
+ import { z } from "zod";
8
+ import type { MCPTool } from "../../../src/mcp/index.js";
9
+ import { type DevError } from "../../../src/observability/index.js";
10
+ import { vfGetProjectContext } from "./project-tools.js";
11
+ import { vfGetConventions } from "./scaffold-tools.js";
12
+ declare const bootstrapInput: z.ZodObject<{
13
+ projectPath: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ type BootstrapInput = z.infer<typeof bootstrapInput>;
16
+ interface BootstrapResult {
17
+ project: Awaited<ReturnType<typeof vfGetProjectContext.execute>>;
18
+ conventions: Awaited<ReturnType<typeof vfGetConventions.execute>>;
19
+ errors: {
20
+ total: number;
21
+ items: DevError[];
22
+ };
23
+ status: {
24
+ running: boolean;
25
+ };
26
+ }
27
+ export declare const vfBootstrap: MCPTool<BootstrapInput, BootstrapResult>;
28
+ export {};
29
+ //# sourceMappingURL=bootstrap-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap-tool.d.ts","sourceRoot":"","sources":["../../../../src/cli/mcp/tools/bootstrap-tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,KAAK,QAAQ,EAAqB,MAAM,qCAAqC,CAAC;AACvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,QAAA,MAAM,cAAc;;iBAIlB,CAAC;AAEH,KAAK,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAErD,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAC;IAC7C,MAAM,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAC9B;AAED,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,cAAc,EAAE,eAAe,CAsChE,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * MCP tool: vf_bootstrap
3
+ *
4
+ * Returns everything an agent needs at session start in a single call:
5
+ * project context, coding conventions, current errors, and server status.
6
+ */
7
+ import { z } from "zod";
8
+ import { getErrorCollector } from "../../../src/observability/index.js";
9
+ import { vfGetProjectContext } from "./project-tools.js";
10
+ import { vfGetConventions } from "./scaffold-tools.js";
11
+ const bootstrapInput = z.object({
12
+ projectPath: z.string().optional().describe("Project directory (defaults to current working directory)"),
13
+ });
14
+ export const vfBootstrap = {
15
+ name: "vf_bootstrap",
16
+ title: "Bootstrap",
17
+ annotations: {
18
+ readOnlyHint: true,
19
+ destructiveHint: false,
20
+ idempotentHint: true,
21
+ openWorldHint: false,
22
+ },
23
+ description: "Use this at the start of a new session to get full project context in one call. " +
24
+ "Returns project structure, coding conventions, current errors, and server status. " +
25
+ "Equivalent to calling vf_get_project_context + vf_get_conventions + vf_get_errors + " +
26
+ "vf_get_status separately, but in a single round-trip. " +
27
+ "Do not use repeatedly — call once at session bootstrap.",
28
+ inputSchema: bootstrapInput,
29
+ execute: async (input) => {
30
+ const [project, conventions] = await Promise.all([
31
+ vfGetProjectContext.execute({ projectPath: input.projectPath }),
32
+ vfGetConventions.execute({ topic: "all" }),
33
+ ]);
34
+ let errors = [];
35
+ let running = false;
36
+ try {
37
+ const collector = getErrorCollector();
38
+ errors = collector.getAll();
39
+ running = true;
40
+ }
41
+ catch {
42
+ running = false;
43
+ }
44
+ return {
45
+ project,
46
+ conventions,
47
+ errors: { total: errors.length, items: errors.slice(-20) },
48
+ status: { running },
49
+ };
50
+ },
51
+ };
@@ -1,3 +1,16 @@
1
+ /**
2
+ * CI/CD MCP tools — placeholder
3
+ *
4
+ * These tools require backend API support that is not yet available.
5
+ * They were previously registered as stubs returning "not_implemented",
6
+ * which misled agents into wasting tool calls.
7
+ *
8
+ * Re-add tools here when the deploy API is available:
9
+ * - vf_get_pipeline_status
10
+ * - vf_get_deploy_history
11
+ * - vf_get_build_logs
12
+ * - vf_trigger_deploy
13
+ */
1
14
  import type { MCPTool } from "../../../src/mcp/index.js";
2
15
  export declare const cicdTools: MCPTool[];
3
16
  //# sourceMappingURL=cicd-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cicd-tools.d.ts","sourceRoot":"","sources":["../../../../src/cli/mcp/tools/cicd-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAuFzD,eAAO,MAAM,SAAS,EAAE,OAAO,EAK9B,CAAC"}
1
+ {"version":3,"file":"cicd-tools.d.ts","sourceRoot":"","sources":["../../../../src/cli/mcp/tools/cicd-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEzD,eAAO,MAAM,SAAS,EAAE,OAAO,EAAO,CAAC"}
@@ -1,83 +1,14 @@
1
- import { z } from "zod";
2
- const getPipelineStatusInput = z.object({
3
- projectSlug: z.string().describe("Project slug"),
4
- environment: z.string().optional().default("production").describe("Target environment"),
5
- });
6
- const vfGetPipelineStatus = {
7
- name: "vf_get_pipeline_status",
8
- title: "Pipeline Status",
9
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
10
- description: "Get the current build/deploy pipeline state for a project environment.",
11
- inputSchema: getPipelineStatusInput,
12
- execute: async (input) => {
13
- return {
14
- status: "not_implemented",
15
- message: "CI/CD pipeline API not yet available. This tool requires backend support.",
16
- projectSlug: input.projectSlug,
17
- environment: input.environment,
18
- };
19
- },
20
- };
21
- const getDeployHistoryInput = z.object({
22
- projectSlug: z.string().describe("Project slug"),
23
- limit: z.number().optional().default(10).describe("Number of recent deployments to return"),
24
- });
25
- const vfGetDeployHistory = {
26
- name: "vf_get_deploy_history",
27
- title: "Deploy History",
28
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
29
- description: "List recent deployments with status, version, URL, and timestamp.",
30
- inputSchema: getDeployHistoryInput,
31
- execute: async (input) => {
32
- return {
33
- status: "not_implemented",
34
- message: "Deploy history API not yet available.",
35
- projectSlug: input.projectSlug,
36
- };
37
- },
38
- };
39
- const getBuildLogsInput = z.object({
40
- projectSlug: z.string().describe("Project slug"),
41
- deployId: z.string().optional().describe("Specific deployment ID (latest if omitted)"),
42
- });
43
- const vfGetBuildLogs = {
44
- name: "vf_get_build_logs",
45
- title: "Build Logs",
46
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
47
- description: "Get build logs from an active or recent build/deployment.",
48
- inputSchema: getBuildLogsInput,
49
- execute: async (input) => {
50
- return {
51
- status: "not_implemented",
52
- message: "Build logs API not yet available.",
53
- projectSlug: input.projectSlug,
54
- };
55
- },
56
- };
57
- const triggerDeployInput = z.object({
58
- projectSlug: z.string().describe("Project slug"),
59
- environment: z.string().optional().default("production").describe("Target environment"),
60
- branch: z.string().optional().default("main").describe("Branch to deploy"),
61
- });
62
- const vfTriggerDeploy = {
63
- name: "vf_trigger_deploy",
64
- title: "Trigger Deploy",
65
- annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
66
- description: "Trigger a deployment to an environment. Returns a deployment ID for status tracking.",
67
- inputSchema: triggerDeployInput,
68
- execute: async (input) => {
69
- return {
70
- status: "not_implemented",
71
- message: "Deploy trigger API not yet available.",
72
- projectSlug: input.projectSlug,
73
- environment: input.environment,
74
- branch: input.branch,
75
- };
76
- },
77
- };
78
- export const cicdTools = [
79
- vfGetPipelineStatus,
80
- vfGetDeployHistory,
81
- vfGetBuildLogs,
82
- vfTriggerDeploy,
83
- ];
1
+ /**
2
+ * CI/CD MCP tools — placeholder
3
+ *
4
+ * These tools require backend API support that is not yet available.
5
+ * They were previously registered as stubs returning "not_implemented",
6
+ * which misled agents into wasting tool calls.
7
+ *
8
+ * Re-add tools here when the deploy API is available:
9
+ * - vf_get_pipeline_status
10
+ * - vf_get_deploy_history
11
+ * - vf_get_build_logs
12
+ * - vf_trigger_deploy
13
+ */
14
+ export const cicdTools = [];
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.211",
3
+ "version": "0.1.213",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -1 +1 @@
1
- {"version":3,"file":"data-stream.d.ts","sourceRoot":"","sources":["../../../src/src/agent/data-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAMzE,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmB1E;AAED,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAwCvF;AAED,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CActF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiB5E;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,CAoBA;AAED,wBAAuB,sBAAsB,CAC3C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,cAAc,CAAC,sBAAsB,CAAC,CAkCxC"}
1
+ {"version":3,"file":"data-stream.d.ts","sourceRoot":"","sources":["../../../src/src/agent/data-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAMzE,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmB1E;AAwBD,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAuDvF;AAED,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAoBtF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiB5E;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG;IACvD,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,CAoBA;AAED,wBAAuB,sBAAsB,CAC3C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,cAAc,CAAC,sBAAsB,CAAC,CAkCxC"}
@@ -17,12 +17,33 @@ export function stripLeadingEmptyObjectPlaceholder(rawArgs) {
17
17
  }
18
18
  return normalized;
19
19
  }
20
+ /**
21
+ * Minimum overlap length at which `mergeToolInputDelta` will accept a
22
+ * tail-overlap as an intentional retransmission from the provider and
23
+ * dedup the leading chunk of the next delta.
24
+ *
25
+ * Empirically, overlaps of 1–3 characters are almost always coincidental
26
+ * in streamed JSON (e.g. `"`, `,`, `":`, `,"`). Accepting them as dedup
27
+ * causes silent character drops — the exact pathology observed in staging
28
+ * on 2026-04-15 where `create_file` tool calls arrived at the classifier
29
+ * with 2–5 chars missing from the middle of the buffer. Requiring at
30
+ * least 4 chars of overlap makes false matches vanishingly unlikely while
31
+ * still honoring the real "retransmitted content-suffix" case pinned by
32
+ * the existing "overlapping suffix dedup" regression test (which relies
33
+ * on a 6-char `Report` overlap).
34
+ *
35
+ * Similarly, short deltas (< 4 chars) are treated as append-mode
36
+ * regardless of what they look like: a 1-char delta literally cannot
37
+ * contain enough signal to distinguish retransmission from append, and
38
+ * we will not silently drop it.
39
+ */
40
+ const MIN_OVERLAP_DEDUP_LENGTH = 4;
20
41
  export function mergeToolInputDelta(currentArguments, nextDelta) {
21
42
  const normalizedDelta = nextDelta.trimStart();
22
43
  const candidateDeltas = normalizedDelta.startsWith('"')
23
44
  ? [normalizedDelta, `{${normalizedDelta}`]
24
45
  : [normalizedDelta];
25
- if (currentArguments === "{}") {
46
+ if (currentArguments === "{}" || currentArguments.length === 0) {
26
47
  for (const candidate of candidateDeltas) {
27
48
  if (candidate.startsWith("{")) {
28
49
  return candidate;
@@ -35,15 +56,29 @@ export function mergeToolInputDelta(currentArguments, nextDelta) {
35
56
  if (currentArguments.length === 0) {
36
57
  return nextDelta;
37
58
  }
59
+ // Short deltas are trusted as append-mode. Retransmission at this size
60
+ // is indistinguishable from append and would produce more corruption
61
+ // than it prevents — see MIN_OVERLAP_DEDUP_LENGTH.
62
+ if (nextDelta.length < MIN_OVERLAP_DEDUP_LENGTH) {
63
+ return currentArguments + nextDelta;
64
+ }
38
65
  for (const candidate of candidateDeltas) {
39
- if (candidate === currentArguments || currentArguments.includes(candidate)) {
66
+ // Exact duplicate: the provider resent the same full buffer.
67
+ if (candidate === currentArguments) {
40
68
  return currentArguments;
41
69
  }
70
+ // Cumulative mode: the delta is a strict extension of the current
71
+ // buffer and supersedes it verbatim.
42
72
  if (candidate.startsWith(currentArguments)) {
43
73
  return candidate;
44
74
  }
75
+ // Tail retransmission: the provider resent a suffix of the current
76
+ // buffer as the prefix of the new delta. Only accept overlaps of
77
+ // MIN_OVERLAP_DEDUP_LENGTH or longer — trivial 1-3 char matches in
78
+ // streamed JSON are overwhelmingly coincidental and deduping them
79
+ // corrupts append-mode streams.
45
80
  const maxOverlap = Math.min(currentArguments.length, candidate.length);
46
- for (let overlap = maxOverlap; overlap > 0; overlap--) {
81
+ for (let overlap = maxOverlap; overlap >= MIN_OVERLAP_DEDUP_LENGTH; overlap--) {
47
82
  if (currentArguments.endsWith(candidate.slice(0, overlap))) {
48
83
  return currentArguments + candidate.slice(overlap);
49
84
  }
@@ -55,9 +90,13 @@ export function mergeToolCallInput(currentArguments, nextInput) {
55
90
  if (currentArguments.length === 0) {
56
91
  return nextInput;
57
92
  }
93
+ const normalizedCurrent = stripLeadingEmptyObjectPlaceholder(currentArguments);
58
94
  if (nextInput.trim() === "{}" && currentArguments.trim().startsWith("{")) {
59
95
  return currentArguments;
60
96
  }
97
+ if (nextInput.trim() === "{}" && normalizedCurrent.trim().startsWith("{")) {
98
+ return normalizedCurrent;
99
+ }
61
100
  if (currentArguments.trim() === "{}" && nextInput.trim().startsWith("{")) {
62
101
  return nextInput;
63
102
  }
@@ -2,4 +2,6 @@ export declare const DEFAULT_MAX_TOKENS: 4096;
2
2
  export declare const DEFAULT_TEMPERATURE: 0.7;
3
3
  export declare const MAX_STREAM_BUFFER_SIZE: number;
4
4
  export declare const DEFAULT_MAX_STEPS = 20;
5
+ /** Look up max output tokens for a model, stripping the `veryfront-cloud/` prefix. */
6
+ export declare function getModelMaxOutputTokens(modelString: string): number | undefined;
5
7
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,MAA2B,CAAC;AAC3D,eAAO,MAAM,mBAAmB,KAA6B,CAAC;AAC9D,eAAO,MAAM,sBAAsB,QAAmC,CAAC;AACvE,eAAO,MAAM,iBAAiB,KAAK,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,MAA2B,CAAC;AAC3D,eAAO,MAAM,mBAAmB,KAA6B,CAAC;AAC9D,eAAO,MAAM,sBAAsB,QAAmC,CAAC;AACvE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAYpC,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK/E"}
@@ -3,3 +3,19 @@ export const DEFAULT_MAX_TOKENS = AGENT_DEFAULTS.maxTokens;
3
3
  export const DEFAULT_TEMPERATURE = AGENT_DEFAULTS.temperature;
4
4
  export const MAX_STREAM_BUFFER_SIZE = STREAMING_DEFAULTS.maxBufferSize;
5
5
  export const DEFAULT_MAX_STEPS = 20;
6
+ /** Max output token limits per model (normalized IDs without `veryfront-cloud/` prefix). */
7
+ const MODEL_MAX_OUTPUT_TOKENS = {
8
+ "anthropic/claude-opus-4-6": 32_768,
9
+ "anthropic/claude-sonnet-4-6": 16_384,
10
+ "anthropic/claude-haiku-4-5-20251001": 8_192,
11
+ "openai/gpt-5.2": 16_384,
12
+ "google-ai-studio/gemini-2.5-pro": 65_536,
13
+ "google-ai-studio/gemini-2.5-flash": 8_192,
14
+ };
15
+ /** Look up max output tokens for a model, stripping the `veryfront-cloud/` prefix. */
16
+ export function getModelMaxOutputTokens(modelString) {
17
+ const normalized = modelString.startsWith("veryfront-cloud/")
18
+ ? modelString.slice("veryfront-cloud/".length)
19
+ : modelString;
20
+ return MODEL_MAX_OUTPUT_TOKENS[normalized];
21
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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"}
@@ -34,7 +34,7 @@ export { executeConfiguredTool, getAvailableTools, isDynamicTool, parseToolArgs,
34
34
  export { accumulateUsage, getMaxSteps, normalizeInput } from "./input-utils.js";
35
35
  export { createStreamState, processStream } from "./chat-stream-handler.js";
36
36
  export { DEFAULT_MAX_STEPS, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE, MAX_STREAM_BUFFER_SIZE, } from "./constants.js";
37
- import { DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from "./constants.js";
37
+ import { DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE, getModelMaxOutputTokens } from "./constants.js";
38
38
  import { closeSSEStream, generateMessageId, sendSSE } from "./sse-utils.js";
39
39
  import { executeConfiguredTool, getAvailableTools, isDynamicTool, parseToolArgs, } from "./tool-helpers.js";
40
40
  import { accumulateUsage, getMaxSteps, normalizeInput } from "./input-utils.js";
@@ -446,7 +446,7 @@ export class AgentRuntime {
446
446
  allowedToolNames: allowedRemoteToolNames,
447
447
  }),
448
448
  experimental_repairToolCall: repairToolCall,
449
- maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
449
+ maxOutputTokens: this.resolveMaxOutputTokens(effectiveModel, maxOutputTokensOverride),
450
450
  temperature: DEFAULT_TEMPERATURE,
451
451
  ...(headers ? { headers } : {}),
452
452
  ...(providerOptions ? { providerOptions } : {}),
@@ -685,7 +685,7 @@ export class AgentRuntime {
685
685
  allowedToolNames: allowedRemoteToolNames,
686
686
  }),
687
687
  experimental_repairToolCall: repairToolCall,
688
- maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
688
+ maxOutputTokens: this.resolveMaxOutputTokens(effectiveModel, maxOutputTokensOverride),
689
689
  temperature: DEFAULT_TEMPERATURE,
690
690
  ...(headers ? { headers } : {}),
691
691
  ...(providerOptions ? { providerOptions } : {}),
@@ -957,13 +957,15 @@ export class AgentRuntime {
957
957
  const edgeMaxSteps = this.config.edge?.enabled ? this.config.edge.maxSteps : undefined;
958
958
  return getMaxSteps(this.config.maxSteps, edgeMaxSteps, platformLimit);
959
959
  }
960
- resolveMaxOutputTokens(maxOutputTokensOverride) {
960
+ resolveMaxOutputTokens(modelString, maxOutputTokensOverride) {
961
961
  if (typeof maxOutputTokensOverride === "number" &&
962
962
  Number.isFinite(maxOutputTokensOverride) &&
963
963
  maxOutputTokensOverride > 0) {
964
964
  return Math.floor(maxOutputTokensOverride);
965
965
  }
966
- return this.config.memory?.maxTokens ?? DEFAULT_MAX_TOKENS;
966
+ return this.config.memory?.maxTokens ??
967
+ (modelString ? getModelMaxOutputTokens(modelString) : undefined) ??
968
+ DEFAULT_MAX_TOKENS;
967
969
  }
968
970
  /**
969
971
  * Get memory instance (for advanced use cases)
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAML,KAAK,kBAAkB,EAIxB,MAAM,oCAAoC,CAAC;AAiB5C,eAAO,MAAM,WAAW,aAAyB,CAAC;AAElD,eAAO,MAAM,aAAa,aAAqD,CAAC;AAEhF,eAAO,MAAM,+BAA+B;;;;;;;;;;2BAc1C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;iBAAgC,CAAC;AACvE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;2BAA+B,CAAC;AACrE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAA2B,CAAC;AAC7D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;6BAA2B,CAAC;AAC7D,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2B,CAAC;AAEnE,eAAO,MAAM,uCAAuC;;;;;;;;;;;;;iBAMlD,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmB3C,CAAC;AAyKH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,GACtD,kBAAkB,CAWpB;AAED,eAAO,MAAM,kBAAkB;;;;;2BAU7B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AACxF,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AACtD,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC1F,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAML,KAAK,kBAAkB,EAIxB,MAAM,oCAAoC,CAAC;AAkB5C,eAAO,MAAM,WAAW,aAAyB,CAAC;AAElD,eAAO,MAAM,aAAa,aAAqD,CAAC;AAEhF,eAAO,MAAM,+BAA+B;;;;;;;;;;2BAc1C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;iBAAgC,CAAC;AACvE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;2BAA+B,CAAC;AACrE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAA2B,CAAC;AAC7D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;6BAA2B,CAAC;AAC7D,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2B,CAAC;AAEnE,eAAO,MAAM,uCAAuC;;;;;;;;;;;;;iBAMlD,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmB3C,CAAC;AAmMH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,GACtD,kBAAkB,CAWpB;AAED,eAAO,MAAM,kBAAkB;;;;;2BAU7B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AACxF,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AACtD,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC1F,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { AgUiRuntimeContextItemSchema, AgUiRuntimeContextSchema, AgUiRuntimeInjectedToolSchema, AgUiRuntimeMessageSchema, AgUiRuntimeRequestSchema, AgUiRuntimeRunIdSchema, } from "../agent/runtime-ag-ui-contract.js";
3
+ import { stripLeadingEmptyObjectPlaceholder } from "../agent/data-stream.js";
3
4
  const AGENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
4
5
  const MAX_FORWARDED_PROPS_BYTES = 65_536;
5
6
  const MAX_TOOL_RESULT_BYTES = 65_536;
@@ -56,10 +57,32 @@ export const InternalAgentStreamRequestSchema = z.object({
56
57
  });
57
58
  function extractToolArgs(part) {
58
59
  const args = part.args;
59
- if (args && typeof args === "object" && !Array.isArray(args)) {
60
+ if (args && typeof args === "object" && !Array.isArray(args) && Object.keys(args).length > 0) {
60
61
  return args;
61
62
  }
62
63
  const input = part.input;
64
+ if (input && typeof input === "object" && !Array.isArray(input) && Object.keys(input).length > 0) {
65
+ return input;
66
+ }
67
+ const inputText = part.inputText;
68
+ if (typeof inputText === "string" && inputText.length > 0) {
69
+ try {
70
+ const normalizedInputText = (() => {
71
+ const stripped = stripLeadingEmptyObjectPlaceholder(inputText);
72
+ return stripped.trimStart().startsWith('"') ? `{${stripped}` : stripped;
73
+ })();
74
+ const parsed = JSON.parse(normalizedInputText);
75
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
76
+ return parsed;
77
+ }
78
+ }
79
+ catch {
80
+ return {};
81
+ }
82
+ }
83
+ if (args && typeof args === "object" && !Array.isArray(args)) {
84
+ return args;
85
+ }
63
86
  if (input && typeof input === "object" && !Array.isArray(input)) {
64
87
  return input;
65
88
  }
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.211";
1
+ export declare const VERSION = "0.1.213";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.211";
3
+ export const VERSION = "0.1.213";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.211",
3
+ "version": "0.1.213",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -26,12 +26,14 @@ import { vfRunLint } from "./tools/run-lint-tool.js";
26
26
  import { vfRunTests } from "./tools/run-tests-tool.js";
27
27
  import { vfGetConventions, vfScaffold } from "./tools/scaffold-tools.js";
28
28
  import { vfGetSkillReference, vfGetSkills } from "./tools/skill-tools.js";
29
+ import { vfBootstrap } from "./tools/bootstrap-tool.js";
29
30
  import { cicdTools } from "./tools/cicd-tools.js";
30
31
  import { introspectionTools } from "./tools/introspection-tools.js";
31
32
 
32
33
  export const advancedTools: MCPTool[] = [
33
34
  ...cicdTools,
34
35
  ...introspectionTools,
36
+ vfBootstrap,
35
37
  vfGetSkills,
36
38
  vfGetSkillReference,
37
39
  vfListLocalProjects,
@@ -467,6 +467,48 @@ export class StandaloneMCPServer {
467
467
  });
468
468
  },
469
469
  },
470
+ {
471
+ name: "vf_bootstrap",
472
+ description:
473
+ "Get full project context in one call: structure, conventions, errors, and server status. " +
474
+ "Use at session start instead of calling vf_get_project_context + vf_get_conventions + " +
475
+ "vf_get_errors + vf_get_status separately.",
476
+ inputSchema: {
477
+ type: "object",
478
+ properties: {
479
+ projectPath: {
480
+ type: "string",
481
+ description: "Project directory (defaults to cwd)",
482
+ },
483
+ },
484
+ },
485
+ async execute(args) {
486
+ const { vfGetProjectContext } = await import("./tools/project-tools.js");
487
+ const { vfGetConventions } = await import("./tools/scaffold-tools.js");
488
+
489
+ const [project, conventions] = await Promise.all([
490
+ vfGetProjectContext.execute({ projectPath: args.projectPath as string }),
491
+ vfGetConventions.execute({ topic: "all" }),
492
+ ]);
493
+
494
+ let errors: unknown[] = [];
495
+ let running = false;
496
+ try {
497
+ const result = await client.getLiveErrors();
498
+ errors = Array.isArray(result) ? result : [];
499
+ running = true;
500
+ } catch {
501
+ // Dev server not running — no errors available
502
+ }
503
+
504
+ return {
505
+ project,
506
+ conventions,
507
+ errors: { total: errors.length, items: errors.slice(-20) },
508
+ status: { running },
509
+ };
510
+ },
511
+ },
470
512
  ...this.createContext7Tools(),
471
513
  ];
472
514
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * MCP tool: vf_bootstrap
3
+ *
4
+ * Returns everything an agent needs at session start in a single call:
5
+ * project context, coding conventions, current errors, and server status.
6
+ */
7
+
8
+ import { z } from "zod";
9
+ import type { MCPTool } from "../../../src/mcp/index.js";
10
+ import { type DevError, getErrorCollector } from "../../../src/observability/index.js";
11
+ import { vfGetProjectContext } from "./project-tools.js";
12
+ import { vfGetConventions } from "./scaffold-tools.js";
13
+
14
+ const bootstrapInput = z.object({
15
+ projectPath: z.string().optional().describe(
16
+ "Project directory (defaults to current working directory)",
17
+ ),
18
+ });
19
+
20
+ type BootstrapInput = z.infer<typeof bootstrapInput>;
21
+
22
+ interface BootstrapResult {
23
+ project: Awaited<ReturnType<typeof vfGetProjectContext.execute>>;
24
+ conventions: Awaited<ReturnType<typeof vfGetConventions.execute>>;
25
+ errors: { total: number; items: DevError[] };
26
+ status: { running: boolean };
27
+ }
28
+
29
+ export const vfBootstrap: MCPTool<BootstrapInput, BootstrapResult> = {
30
+ name: "vf_bootstrap",
31
+ title: "Bootstrap",
32
+ annotations: {
33
+ readOnlyHint: true,
34
+ destructiveHint: false,
35
+ idempotentHint: true,
36
+ openWorldHint: false,
37
+ },
38
+ description: "Use this at the start of a new session to get full project context in one call. " +
39
+ "Returns project structure, coding conventions, current errors, and server status. " +
40
+ "Equivalent to calling vf_get_project_context + vf_get_conventions + vf_get_errors + " +
41
+ "vf_get_status separately, but in a single round-trip. " +
42
+ "Do not use repeatedly — call once at session bootstrap.",
43
+ inputSchema: bootstrapInput,
44
+ execute: async (input) => {
45
+ const [project, conventions] = await Promise.all([
46
+ vfGetProjectContext.execute({ projectPath: input.projectPath }),
47
+ vfGetConventions.execute({ topic: "all" }),
48
+ ]);
49
+
50
+ let errors: DevError[] = [];
51
+ let running = false;
52
+ try {
53
+ const collector = getErrorCollector();
54
+ errors = collector.getAll();
55
+ running = true;
56
+ } catch {
57
+ running = false;
58
+ }
59
+
60
+ return {
61
+ project,
62
+ conventions,
63
+ errors: { total: errors.length, items: errors.slice(-20) },
64
+ status: { running },
65
+ };
66
+ },
67
+ };
@@ -1,94 +1,17 @@
1
- import { z } from "zod";
2
- import type { MCPTool } from "../../../src/mcp/index.js";
3
-
4
- const getPipelineStatusInput = z.object({
5
- projectSlug: z.string().describe("Project slug"),
6
- environment: z.string().optional().default("production").describe("Target environment"),
7
- });
8
-
9
- const vfGetPipelineStatus: MCPTool = {
10
- name: "vf_get_pipeline_status",
11
- title: "Pipeline Status",
12
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
13
- description: "Get the current build/deploy pipeline state for a project environment.",
14
- inputSchema: getPipelineStatusInput,
15
- execute: async (input: { projectSlug: string; environment: string }) => {
16
- return {
17
- status: "not_implemented",
18
- message: "CI/CD pipeline API not yet available. This tool requires backend support.",
19
- projectSlug: input.projectSlug,
20
- environment: input.environment,
21
- };
22
- },
23
- };
24
-
25
- const getDeployHistoryInput = z.object({
26
- projectSlug: z.string().describe("Project slug"),
27
- limit: z.number().optional().default(10).describe("Number of recent deployments to return"),
28
- });
29
-
30
- const vfGetDeployHistory: MCPTool = {
31
- name: "vf_get_deploy_history",
32
- title: "Deploy History",
33
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
34
- description: "List recent deployments with status, version, URL, and timestamp.",
35
- inputSchema: getDeployHistoryInput,
36
- execute: async (input: { projectSlug: string; limit: number }) => {
37
- return {
38
- status: "not_implemented",
39
- message: "Deploy history API not yet available.",
40
- projectSlug: input.projectSlug,
41
- };
42
- },
43
- };
1
+ /**
2
+ * CI/CD MCP tools placeholder
3
+ *
4
+ * These tools require backend API support that is not yet available.
5
+ * They were previously registered as stubs returning "not_implemented",
6
+ * which misled agents into wasting tool calls.
7
+ *
8
+ * Re-add tools here when the deploy API is available:
9
+ * - vf_get_pipeline_status
10
+ * - vf_get_deploy_history
11
+ * - vf_get_build_logs
12
+ * - vf_trigger_deploy
13
+ */
44
14
 
45
- const getBuildLogsInput = z.object({
46
- projectSlug: z.string().describe("Project slug"),
47
- deployId: z.string().optional().describe("Specific deployment ID (latest if omitted)"),
48
- });
49
-
50
- const vfGetBuildLogs: MCPTool = {
51
- name: "vf_get_build_logs",
52
- title: "Build Logs",
53
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
54
- description: "Get build logs from an active or recent build/deployment.",
55
- inputSchema: getBuildLogsInput,
56
- execute: async (input: { projectSlug: string; deployId?: string }) => {
57
- return {
58
- status: "not_implemented",
59
- message: "Build logs API not yet available.",
60
- projectSlug: input.projectSlug,
61
- };
62
- },
63
- };
64
-
65
- const triggerDeployInput = z.object({
66
- projectSlug: z.string().describe("Project slug"),
67
- environment: z.string().optional().default("production").describe("Target environment"),
68
- branch: z.string().optional().default("main").describe("Branch to deploy"),
69
- });
70
-
71
- const vfTriggerDeploy: MCPTool = {
72
- name: "vf_trigger_deploy",
73
- title: "Trigger Deploy",
74
- annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
75
- description:
76
- "Trigger a deployment to an environment. Returns a deployment ID for status tracking.",
77
- inputSchema: triggerDeployInput,
78
- execute: async (input: { projectSlug: string; environment: string; branch: string }) => {
79
- return {
80
- status: "not_implemented",
81
- message: "Deploy trigger API not yet available.",
82
- projectSlug: input.projectSlug,
83
- environment: input.environment,
84
- branch: input.branch,
85
- };
86
- },
87
- };
15
+ import type { MCPTool } from "../../../src/mcp/index.js";
88
16
 
89
- export const cicdTools: MCPTool[] = [
90
- vfGetPipelineStatus,
91
- vfGetDeployHistory,
92
- vfGetBuildLogs,
93
- vfTriggerDeploy,
94
- ];
17
+ export const cicdTools: MCPTool[] = [];
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.211",
3
+ "version": "0.1.213",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -25,13 +25,35 @@ export function stripLeadingEmptyObjectPlaceholder(rawArgs: string): string {
25
25
  return normalized;
26
26
  }
27
27
 
28
+ /**
29
+ * Minimum overlap length at which `mergeToolInputDelta` will accept a
30
+ * tail-overlap as an intentional retransmission from the provider and
31
+ * dedup the leading chunk of the next delta.
32
+ *
33
+ * Empirically, overlaps of 1–3 characters are almost always coincidental
34
+ * in streamed JSON (e.g. `"`, `,`, `":`, `,"`). Accepting them as dedup
35
+ * causes silent character drops — the exact pathology observed in staging
36
+ * on 2026-04-15 where `create_file` tool calls arrived at the classifier
37
+ * with 2–5 chars missing from the middle of the buffer. Requiring at
38
+ * least 4 chars of overlap makes false matches vanishingly unlikely while
39
+ * still honoring the real "retransmitted content-suffix" case pinned by
40
+ * the existing "overlapping suffix dedup" regression test (which relies
41
+ * on a 6-char `Report` overlap).
42
+ *
43
+ * Similarly, short deltas (< 4 chars) are treated as append-mode
44
+ * regardless of what they look like: a 1-char delta literally cannot
45
+ * contain enough signal to distinguish retransmission from append, and
46
+ * we will not silently drop it.
47
+ */
48
+ const MIN_OVERLAP_DEDUP_LENGTH = 4;
49
+
28
50
  export function mergeToolInputDelta(currentArguments: string, nextDelta: string): string {
29
51
  const normalizedDelta = nextDelta.trimStart();
30
52
  const candidateDeltas = normalizedDelta.startsWith('"')
31
53
  ? [normalizedDelta, `{${normalizedDelta}`]
32
54
  : [normalizedDelta];
33
55
 
34
- if (currentArguments === "{}") {
56
+ if (currentArguments === "{}" || currentArguments.length === 0) {
35
57
  for (const candidate of candidateDeltas) {
36
58
  if (candidate.startsWith("{")) {
37
59
  return candidate;
@@ -47,17 +69,32 @@ export function mergeToolInputDelta(currentArguments: string, nextDelta: string)
47
69
  return nextDelta;
48
70
  }
49
71
 
72
+ // Short deltas are trusted as append-mode. Retransmission at this size
73
+ // is indistinguishable from append and would produce more corruption
74
+ // than it prevents — see MIN_OVERLAP_DEDUP_LENGTH.
75
+ if (nextDelta.length < MIN_OVERLAP_DEDUP_LENGTH) {
76
+ return currentArguments + nextDelta;
77
+ }
78
+
50
79
  for (const candidate of candidateDeltas) {
51
- if (candidate === currentArguments || currentArguments.includes(candidate)) {
80
+ // Exact duplicate: the provider resent the same full buffer.
81
+ if (candidate === currentArguments) {
52
82
  return currentArguments;
53
83
  }
54
84
 
85
+ // Cumulative mode: the delta is a strict extension of the current
86
+ // buffer and supersedes it verbatim.
55
87
  if (candidate.startsWith(currentArguments)) {
56
88
  return candidate;
57
89
  }
58
90
 
91
+ // Tail retransmission: the provider resent a suffix of the current
92
+ // buffer as the prefix of the new delta. Only accept overlaps of
93
+ // MIN_OVERLAP_DEDUP_LENGTH or longer — trivial 1-3 char matches in
94
+ // streamed JSON are overwhelmingly coincidental and deduping them
95
+ // corrupts append-mode streams.
59
96
  const maxOverlap = Math.min(currentArguments.length, candidate.length);
60
- for (let overlap = maxOverlap; overlap > 0; overlap--) {
97
+ for (let overlap = maxOverlap; overlap >= MIN_OVERLAP_DEDUP_LENGTH; overlap--) {
61
98
  if (currentArguments.endsWith(candidate.slice(0, overlap))) {
62
99
  return currentArguments + candidate.slice(overlap);
63
100
  }
@@ -72,10 +109,16 @@ export function mergeToolCallInput(currentArguments: string, nextInput: string):
72
109
  return nextInput;
73
110
  }
74
111
 
112
+ const normalizedCurrent = stripLeadingEmptyObjectPlaceholder(currentArguments);
113
+
75
114
  if (nextInput.trim() === "{}" && currentArguments.trim().startsWith("{")) {
76
115
  return currentArguments;
77
116
  }
78
117
 
118
+ if (nextInput.trim() === "{}" && normalizedCurrent.trim().startsWith("{")) {
119
+ return normalizedCurrent;
120
+ }
121
+
79
122
  if (currentArguments.trim() === "{}" && nextInput.trim().startsWith("{")) {
80
123
  return nextInput;
81
124
  }
@@ -4,3 +4,21 @@ export const DEFAULT_MAX_TOKENS = AGENT_DEFAULTS.maxTokens;
4
4
  export const DEFAULT_TEMPERATURE = AGENT_DEFAULTS.temperature;
5
5
  export const MAX_STREAM_BUFFER_SIZE = STREAMING_DEFAULTS.maxBufferSize;
6
6
  export const DEFAULT_MAX_STEPS = 20;
7
+
8
+ /** Max output token limits per model (normalized IDs without `veryfront-cloud/` prefix). */
9
+ const MODEL_MAX_OUTPUT_TOKENS: Record<string, number> = {
10
+ "anthropic/claude-opus-4-6": 32_768,
11
+ "anthropic/claude-sonnet-4-6": 16_384,
12
+ "anthropic/claude-haiku-4-5-20251001": 8_192,
13
+ "openai/gpt-5.2": 16_384,
14
+ "google-ai-studio/gemini-2.5-pro": 65_536,
15
+ "google-ai-studio/gemini-2.5-flash": 8_192,
16
+ };
17
+
18
+ /** Look up max output tokens for a model, stripping the `veryfront-cloud/` prefix. */
19
+ export function getModelMaxOutputTokens(modelString: string): number | undefined {
20
+ const normalized = modelString.startsWith("veryfront-cloud/")
21
+ ? modelString.slice("veryfront-cloud/".length)
22
+ : modelString;
23
+ return MODEL_MAX_OUTPUT_TOKENS[normalized];
24
+ }
@@ -87,7 +87,7 @@ export {
87
87
  MAX_STREAM_BUFFER_SIZE,
88
88
  } from "./constants.js";
89
89
 
90
- import { DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from "./constants.js";
90
+ import { DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE, getModelMaxOutputTokens } from "./constants.js";
91
91
  import { closeSSEStream, generateMessageId, sendSSE } from "./sse-utils.js";
92
92
  import {
93
93
  executeConfiguredTool,
@@ -726,7 +726,7 @@ export class AgentRuntime {
726
726
  allowedToolNames: allowedRemoteToolNames,
727
727
  }),
728
728
  experimental_repairToolCall: repairToolCall,
729
- maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
729
+ maxOutputTokens: this.resolveMaxOutputTokens(effectiveModel, maxOutputTokensOverride),
730
730
  temperature: DEFAULT_TEMPERATURE,
731
731
  ...(headers ? { headers } : {}),
732
732
  ...(providerOptions ? { providerOptions } : {}),
@@ -1033,7 +1033,7 @@ export class AgentRuntime {
1033
1033
  allowedToolNames: allowedRemoteToolNames,
1034
1034
  }),
1035
1035
  experimental_repairToolCall: repairToolCall,
1036
- maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
1036
+ maxOutputTokens: this.resolveMaxOutputTokens(effectiveModel, maxOutputTokensOverride),
1037
1037
  temperature: DEFAULT_TEMPERATURE,
1038
1038
  ...(headers ? { headers } : {}),
1039
1039
  ...(providerOptions ? { providerOptions } : {}),
@@ -1378,7 +1378,7 @@ export class AgentRuntime {
1378
1378
  return getMaxSteps(this.config.maxSteps, edgeMaxSteps, platformLimit);
1379
1379
  }
1380
1380
 
1381
- private resolveMaxOutputTokens(maxOutputTokensOverride?: number): number {
1381
+ private resolveMaxOutputTokens(modelString?: string, maxOutputTokensOverride?: number): number {
1382
1382
  if (
1383
1383
  typeof maxOutputTokensOverride === "number" &&
1384
1384
  Number.isFinite(maxOutputTokensOverride) &&
@@ -1387,7 +1387,9 @@ export class AgentRuntime {
1387
1387
  return Math.floor(maxOutputTokensOverride);
1388
1388
  }
1389
1389
 
1390
- return this.config.memory?.maxTokens ?? DEFAULT_MAX_TOKENS;
1390
+ return this.config.memory?.maxTokens ??
1391
+ (modelString ? getModelMaxOutputTokens(modelString) : undefined) ??
1392
+ DEFAULT_MAX_TOKENS;
1391
1393
  }
1392
1394
 
1393
1395
  /**
@@ -10,6 +10,7 @@ import {
10
10
  AgUiRuntimeRunIdSchema,
11
11
  AgUiRuntimeToolCallSchema,
12
12
  } from "../agent/runtime-ag-ui-contract.js";
13
+ import { stripLeadingEmptyObjectPlaceholder } from "../agent/data-stream.js";
13
14
 
14
15
  const AGENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
15
16
  const MAX_FORWARDED_PROPS_BYTES = 65_536;
@@ -88,11 +89,37 @@ function extractToolArgs(
88
89
  part: Record<string, unknown>,
89
90
  ): Record<string, unknown> {
90
91
  const args = part.args;
91
- if (args && typeof args === "object" && !Array.isArray(args)) {
92
+ if (args && typeof args === "object" && !Array.isArray(args) && Object.keys(args).length > 0) {
92
93
  return args as Record<string, unknown>;
93
94
  }
94
95
 
95
96
  const input = part.input;
97
+ if (
98
+ input && typeof input === "object" && !Array.isArray(input) && Object.keys(input).length > 0
99
+ ) {
100
+ return input as Record<string, unknown>;
101
+ }
102
+
103
+ const inputText = part.inputText;
104
+ if (typeof inputText === "string" && inputText.length > 0) {
105
+ try {
106
+ const normalizedInputText = (() => {
107
+ const stripped = stripLeadingEmptyObjectPlaceholder(inputText);
108
+ return stripped.trimStart().startsWith('"') ? `{${stripped}` : stripped;
109
+ })();
110
+ const parsed = JSON.parse(normalizedInputText);
111
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
112
+ return parsed as Record<string, unknown>;
113
+ }
114
+ } catch {
115
+ return {};
116
+ }
117
+ }
118
+
119
+ if (args && typeof args === "object" && !Array.isArray(args)) {
120
+ return args as Record<string, unknown>;
121
+ }
122
+
96
123
  if (input && typeof input === "object" && !Array.isArray(input)) {
97
124
  return input as Record<string, unknown>;
98
125
  }
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.211";
3
+ export const VERSION = "0.1.213";