veryfront 0.1.212 → 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.
@@ -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.212",
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,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"}
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,6 +17,27 @@ 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('"')
@@ -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
  }
@@ -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.212";
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.212";
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.212",
3
+ "version": "0.1.213",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -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.212",
3
+ "version": "0.1.213",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -25,6 +25,28 @@ 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('"')
@@ -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
  }
@@ -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.212";
3
+ export const VERSION = "0.1.213";