Skip to content

fix(copilot): standardize entity tool contracts and review hydration#139

Merged
BWJ2310-backup merged 2 commits into
mainfrom
staging
Jun 6, 2026
Merged

fix(copilot): standardize entity tool contracts and review hydration#139
BWJ2310-backup merged 2 commits into
mainfrom
staging

Conversation

@BWJ2310-backup

Copy link
Copy Markdown
Contributor

Summary

Promotes the current staging branch into upstream/main.

  • Standardizes Copilot tool contracts around entityId and entityDocument across client tools, server tools, prompt metadata, manifests, execution context, and tests.
  • Adds shared helpers for entity target resolution, workflow-scoped server permissions, staged review persistence, and custom tool schema validation.
  • Persists and hydrates staged Copilot review results so accepted workflow/entity previews survive reloads and full-access mode can auto-accept eligible review tools.
  • Rebuilds plan todos from persisted tool results and carries tool result data through streaming UI state.
  • Updates focused Copilot tests, waitlist copy, and the June 6 changelog.

Why

This removes workflow-specific Copilot boundary contracts, reduces schema drift between client/server/custom tool paths, and makes staged tool review behavior durable across hydration and reloads.

Affected Areas

  • apps/tradinggoose
  • apps/docs
  • packages/*
  • Workflows / execution
  • Realtime / sockets
  • Market data / charting
  • Dev tooling / CI / infra
  • Documentation only
  • Other: Copilot tool contracts, staged review hydration, custom tool schema validation

Issue Links( if any )

Refs #138

Validation

git fetch upstream main
git diff --shortstat upstream/main...HEAD
# 82 files changed, 1391 insertions(+), 1041 deletions(-)

bun run test -- app/api/copilot/chat/review-session-post.test.ts lib/copilot/inline-tool-call.test.tsx lib/copilot/runtime-tool-manifest.test.ts lib/copilot/server-tool-errors.test.ts lib/copilot/tools/client/entities/entity-tools.test.ts lib/copilot/tools/client/monitor/monitor-tools.test.ts lib/copilot/tools/client/workflow/block-output-tools.test.ts lib/copilot/tools/client/workflow/deploy-workflow.test.ts lib/copilot/tools/client/workflow/edit-workflow-block.test.ts lib/copilot/tools/client/workflow/edit-workflow.test.ts lib/copilot/tools/client/workflow/run-workflow.test.ts lib/copilot/tools/client/workflow/set-workflow-variables.test.ts lib/copilot/tools/client/workflow/workflow-metadata-tools.test.ts lib/copilot/tools/client/workflow/workflow-review-tool-utils.test.ts lib/copilot/tools/server/agent/get-agent-accessory-catalog.test.ts lib/copilot/tools/server/gdrive/list-files.test.ts lib/copilot/tools/server/gdrive/read-file.test.ts lib/copilot/tools/server/router.test.ts lib/copilot/tools/server/user/read-environment-variables.test.ts lib/copilot/tools/server/workflow/edit-workflow-block.test.ts lib/copilot/tools/server/workflow/edit-workflow.test.ts lib/copilot/tools/server/workflow/read-workflow-logs.test.ts stores/copilot/store-provenance.test.ts stores/copilot/store.test.ts stores/copilot/tool-registry.test.ts
# PASS: 25 test files, 150 tests

bun run check
# FAIL: existing Biome formatting/class-sort/import diagnostics in apps/docs and .devcontainer.
# Confirmed those paths are outside this PR diff with:
# git diff --name-only upstream/main...HEAD -- apps/docs .devcontainer

Risk / Rollout Notes

Moderate Copilot risk because tool arguments and persisted execution provenance move from workflow-specific fields to entity-scoped fields. Key paths to watch after rollout: Copilot workflow edits, workflow runs/deployments, staged review accept/reject flows, custom tool import/upsert, and Google Drive/workspace-scoped server tools.

Backout: revert the merge commit from main, or revert commit 2777a382 if applied directly.

Config / Data Changes

  • Env vars added or changed: None.
  • Database schema or migration impact: None; no migration files are included.
  • External services or provider behavior changed: No provider contract changes. Google Drive/server tools now resolve workflow-scoped access through explicit entityId or context before listing/reading resources.

Screenshots / Video

Not captured. The visible changes are limited to Copilot inline tool review state rendering and waitlist copy; no broad layout changes are included.

Checklist

  • I kept the change focused and reviewed my own diff
  • I validated the change locally and documented the results above
  • I updated docs, examples, or copy if behavior/user-facing flows changed
  • I called out any env, schema, provider, or rollout impact
  • I did not include secrets, tokens, or private credentials in this PR

…138)

* feat(copilot): standardize entity-scoped tool contracts

Unify workflow and custom tool request shapes around entity ids/documents, tighten custom tool schema validation, and thread the new provenance through client and server tool execution.\n\nCo-authored-by: Codex <codex@openai.com>

* feat(copilot): persist staged tool review state

Add reusable staged-review handling for client tools, hydrate plan todos from persisted messages, and carry tool result data through the streaming UI.

Co-authored-by: Codex <codex@openai.com>

* fix(i18n): update waitlist text and format JSON for consistency

* feat(copilot): enhance tool validation descriptions and auto-execute eligible tools based on access level

* fix(copilot): enhance tool validation and auto-execution logic for access levels

* fix(copilot): streamline plan todos hydration by filtering for successful tool calls

* fix(copilot): refactor tool execution logic and enhance message handling for pending tools

* fix(copilot): enhance tool call handling by ensuring unique tool call IDs and updating test cases for accuracy

---------

Co-authored-by: Codex <codex@openai.com>
@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
studio (staging) Ready Ready Preview, Comment Jun 6, 2026 10:13pm

Request Review

@greptile-apps

greptile-apps Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR completes the migration of Copilot tool contracts from workflow-specific fields (workflowId, workflowDocument, contextWorkflowId) to the canonical entity-scoped fields (entityId, entityDocument, contextEntityKind/contextEntityId) across client tools, server tools, schemas, manifests, and the provenance layer. It also adds staged-review hydration so accepted workflow/entity previews survive page reloads, rebuilds plan todos from persisted contentBlocks tool results on chat load, and soft-retires the tool_calls DB column in favor of contentBlocks.

  • Schema standardisation: entityId / entityDocument replace workflowId / workflowDocument in every ToolArgSchema, server tool param interface, and execution context; StagedReviewClientTool base class centralises staged-preview lifecycle; workflow-scope.ts and entity-target.ts provide shared helpers.
  • Streaming & state management: auto-tool-execution is now awaited sequentially before the final turn-status is committed, so resolveFinalStreamTurnState correctly reflects post-execution tool states; tool result data is threaded through the streaming display state for the first time.
  • Persistence cleanup: chat/route.ts converts LLM toolCalls responses to contentBlocks format on persist; all normalisation and LLM-context paths drop the legacy toolCalls branch; the Drizzle schema removes the tool_calls column definition (soft deprecation with no DDL migration required given the column default)."

Confidence Score: 4/5

Safe to merge for new sessions; any user mid-session at deployment time will see tool-call failures until they start a fresh chat.

prepareCopilotToolArgs now runs strict Zod validation using the new entityId/entityDocument schemas. Sessions whose LLM received the old manifest (with workflowId/workflowDocument) will produce args that fail the strict parse, causing every workflow-mutation tool call to surface as a client error for those users. The issue is self-healing — starting a new chat picks up the updated manifest — but it is a silent breaking point for any in-progress session at the moment of deployment.

apps/tradinggoose/stores/copilot/tool-registry.ts (prepareCopilotToolArgs); apps/tradinggoose/lib/copilot/registry.ts (strict-mode workflow schemas)

Important Files Changed

Filename Overview
apps/tradinggoose/stores/copilot/tool-registry.ts Adds handleCopilotServerToolSuccess helper and moves environment-store reload into it; renames provenance fields from workflowId/contextWorkflowId to contextEntityKind/contextEntityId; prepareCopilotToolArgs now strict-parses args through Zod schemas, which can reject old-format args from in-flight sessions
apps/tradinggoose/stores/copilot/store-messages.ts Drops legacy toolCalls array processing from normalizeMessagesForUI, buildPinnedToolCallsById, updateMessagesForToolCallState, and validateMessagesForLLM; adds buildPlanTodosFromMessages to rebuild plan todo state from persisted contentBlocks-format tool results using canonical id field
apps/tradinggoose/stores/copilot/store-provenance.ts Migrates provenance from contextWorkflowId/workflowId to contextEntityKind/contextEntityId; non-workflow reviewTarget no longer propagates entityId, reviewSessionId, or draftSessionId into provenance — only workspaceId is carried forward; removes toolCalls-based lookup from findAssistantMessageIdForToolCall
apps/tradinggoose/stores/copilot/store.ts Reorders stream-completion flow so resolveFinalStreamTurnState and abort-controller cleanup run after flushPendingAutoExecutionToolCalls; removes review state from access-level auto-execution; wires buildPlanTodoStateFromMessages into all chat-load and sync paths
apps/tradinggoose/stores/copilot/streaming.ts Converts auto-tool execution from fire-and-forget setTimeout to sequential await; pipes tool result through buildStreamedToolDisplayState so result data is visible in streaming UI state; awaiting_tools handler now sets latestTurnStatus = ACTIVE_TURN_STATUS and awaitingTools = true
apps/tradinggoose/lib/copilot/tools/client/base-tool.ts Extracts StagedReviewClientTool abstract base class with stageReviewResult, getStagedReviewResult, and prepareReviewAccept lifecycle; removes per-tool lastResult fields and getInterruptDisplays overrides
apps/tradinggoose/lib/copilot/tools/entity-target.ts New shared helper for canonical entityId / contextEntityKind resolution across client and server tools
apps/tradinggoose/lib/copilot/tools/server/workflow/workflow-scope.ts New helper centralizing workflow-scoped server access: resolveServerWorkflowScope verifies access via verifyWorkflowAccess; resolveServerWorkspaceId falls back to context.workspaceId when no workflow scope is resolved
apps/tradinggoose/app/api/copilot/execute-copilot-server-tool/route.ts Adds explicit workspace membership check when context.workspaceId is present; schema extended with contextEntityKind, contextEntityId, workspaceId
apps/tradinggoose/app/api/copilot/chat/route.ts Removes toolCalls from persistence path; converts LLM responseData.toolCalls to contentBlocks format on the non-SSE persist path, completing the migration away from the legacy column
packages/db/schema/copilot.ts Removes tool_calls column from the Drizzle ORM model (soft deprecation — no DDL migration needed since the column has a default and existing data is simply abandoned)
apps/tradinggoose/lib/custom-tools/schema.ts New Zod schemas (CustomToolParametersSchema, CustomToolOpenAiSchema, CustomToolUpsertRequestSchema) centralizing custom-tool document validation; introduces parseCustomToolSchemaText replacing the inline JSON.parse path
apps/tradinggoose/lib/copilot/runtime-tool-manifest-enrichment.ts Simplifies semantic validators by inlining JSON-schema constants for TG_WORKFLOW, TG_BLOCK, and TG_EDGE metadata; removes AnnotatedGraphDocumentContract / string_document_contract path and the dynamic buildWorkflowEmbeddedDocumentValidators async import; switches preferredDocumentField from workflowDocument to entityDocument
apps/tradinggoose/lib/copilot/inline-tool-call.tsx Review payload now visible in both review and success states; readEntityReviewPayload guards on result.entityKind presence instead of a hardcoded tool-name list; title changes to "Applied … Changes" in success state

Sequence Diagram

sequenceDiagram
    participant LLM
    participant StreamHandler as SSE StreamHandler
    participant ToolRegistry as prepareCopilotToolArgs (Zod parse)
    participant ClientTool as StagedReviewClientTool
    participant ServerRoute as /execute-copilot-server-tool
    participant WorkflowScope as resolveServerWorkflowScope
    participant DB

    LLM->>StreamHandler: "tool_call {entityId, entityDocument}"
    StreamHandler->>StreamHandler: applyStreamedFunctionCallItem
    StreamHandler->>StreamHandler: stream_complete
    StreamHandler->>ToolRegistry: executeCopilotToolCall
    ToolRegistry->>ToolRegistry: ToolArgSchemas[name].parse(args) strict
    ToolRegistry->>ClientTool: execute(args)
    ClientTool->>ServerRoute: "executeCopilotServerTool({entityId, workspaceId})"
    ServerRoute->>ServerRoute: checkWorkspaceAccess(workspaceId, userId)
    ServerRoute->>WorkflowScope: resolveServerWorkflowScope(params, context)
    WorkflowScope->>WorkflowScope: verifyWorkflowAccess(userId, entityId)
    WorkflowScope-->>ServerRoute: "{workflowId, workspaceId, hasAccess}"
    ServerRoute-->>ClientTool: staged result
    ClientTool->>ClientTool: stageReviewResult(result) setState(review)
    ClientTool-->>StreamHandler: awaited
    StreamHandler->>StreamHandler: resolveFinalStreamTurnState
    StreamHandler->>DB: persistChatMessages(contentBlocks)
    DB-->>StreamHandler: ok
    Note over StreamHandler: On reload: buildPlanTodosFromMessages(contentBlocks)
Loading

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/tradinggoose/stores/copilot/tool-registry.ts:275-288
**Strict Zod parse rejects in-flight session args after deployment**

`prepareCopilotToolArgs` now calls `ToolArgSchemas[toolName].parse(clonedArgs)` for every known tool. Schemas for `edit_workflow`, `rename_workflow`, `deploy_workflow`, `run_workflow`, `check_deployment_status`, `read_workflow`, `read_workflow_variables`, `set_workflow_variables`, and `read_workflow_logs` are all `.strict()` and now require `entityId` / `entityDocument` (not `workflowId` / `workflowDocument`). Any Copilot session that was opened before this deployment — where the LLM received the old manifest — will generate args containing `workflowId` / `workflowDocument`. The strict parse will throw a `ZodError`, the tool execution will surface as a client-side error, and the user must start a fresh session to recover. The old path returned `cloneArgs(args)` unconditionally, so this is a new failure mode with no graceful degradation.

Reviews (2): Last reviewed commit: "fix(copilot): normalize tool parameter h..." | Re-trigger Greptile

Comment thread apps/tradinggoose/stores/copilot/store-messages.ts
Comment on lines 292 to 293
throw new Error('No active workspace found')
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 resolveWorkspaceIdFromExecutionContext no longer has any fallback

The removed workflowId registry lookup was the only fallback for contexts where workspaceId wasn't set explicitly in the execution context. Now if executionContext.workspaceId is absent, the function throws immediately. This regresses any entity tool call (create/edit skill, indicator, etc.) that arrives from a Copilot session where workspaceId wasn't forwarded into provenance — for example, edge cases where the reviewTarget had no workspaceId or where buildTurnProvenanceFromContexts returned undefined (see separate comment on store-provenance.ts). Adding even a simple error context to the thrown error would make diagnosing this in production much easier.

Suggested change
throw new Error('No active workspace found')
}
throw new Error(
'No active workspace found in execution context. Ensure workspaceId is included in tool provenance.'
)
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/tradinggoose/lib/copilot/tools/client/entities/entity-document-tool-utils.ts
Line: 292-293

Comment:
**`resolveWorkspaceIdFromExecutionContext` no longer has any fallback**

The removed `workflowId` registry lookup was the only fallback for contexts where `workspaceId` wasn't set explicitly in the execution context. Now if `executionContext.workspaceId` is absent, the function throws immediately. This regresses any entity tool call (create/edit skill, indicator, etc.) that arrives from a Copilot session where `workspaceId` wasn't forwarded into provenance — for example, edge cases where the `reviewTarget` had no `workspaceId` or where `buildTurnProvenanceFromContexts` returned `undefined` (see separate comment on `store-provenance.ts`). Adding even a simple error context to the thrown error would make diagnosing this in production much easier.

```suggestion
  throw new Error(
    'No active workspace found in execution context. Ensure workspaceId is included in tool provenance.'
  )
}
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex Fix in Claude Code Fix in Cursor

Comment on lines +6 to +10
export const CustomToolParametersSchema = z.object({
type: z.literal('object'),
properties: z.record(z.any()),
required: z.array(z.string()).optional(),
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 CustomToolParametersSchema tightens type to z.literal('object') which could reject existing persisted schemas

The old schema accepted any string for parameters.type. The new CustomToolUpsertRequestSchema (consumed by the POST /api/tools/custom endpoint) and parseCustomToolSchemaText (used when Copilot submits a custom tool document) now both require type: 'object' exactly. Any existing workspace with a custom tool whose stored schema has parameters.type set to a different value (e.g. previously created through a less-strict code path) will receive a Zod parse error on the next Copilot edit or API upsert, silently blocking that tool from being updated.

Suggested change
export const CustomToolParametersSchema = z.object({
type: z.literal('object'),
properties: z.record(z.any()),
required: z.array(z.string()).optional(),
})
export const CustomToolParametersSchema = z.object({
type: z.union([z.literal('object'), z.string()]).transform(() => 'object' as const),
properties: z.record(z.any()),
required: z.array(z.string()).optional(),
})
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/tradinggoose/lib/custom-tools/schema.ts
Line: 6-10

Comment:
**`CustomToolParametersSchema` tightens `type` to `z.literal('object')` which could reject existing persisted schemas**

The old schema accepted any string for `parameters.type`. The new `CustomToolUpsertRequestSchema` (consumed by the POST `/api/tools/custom` endpoint) and `parseCustomToolSchemaText` (used when Copilot submits a custom tool document) now both require `type: 'object'` exactly. Any existing workspace with a custom tool whose stored schema has `parameters.type` set to a different value (e.g. previously created through a less-strict code path) will receive a Zod parse error on the next Copilot edit or API upsert, silently blocking that tool from being updated.

```suggestion
export const CustomToolParametersSchema = z.object({
  type: z.union([z.literal('object'), z.string()]).transform(() => 'object' as const),
  properties: z.record(z.any()),
  required: z.array(z.string()).optional(),
})
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex Fix in Claude Code Fix in Cursor

* fix(copilot): refine tool parameter handling and enhance error messages

* fix(copilot): remove obsolete custom tool schema tests and update streaming handlers

* refactor(copilot): remove legacy assistant toolCalls state

Migrate Copilot message persistence and rendering to content blocks.

Co-authored-by: Codex <codex@openai.com>

* fix(copilot): propagate workspace context through server tools

Validate server tool arguments and carry workspace context through Copilot execution.

Co-authored-by: Codex <codex@openai.com>

* refactor(copilot): simplify workflow document validators

Remove the obsolete workflow document contract from Copilot manifest enrichment.

Co-authored-by: Codex <codex@openai.com>

* fix(copilot): update streaming logic and refine tool execution handling

* fix(copilot): standardize tool argument handling and remove legacy toolCalls schema

* fix(copilot): enhance tool argument handling and implement workspace access checks

* fix(copilot): update todo execution state handling in tests and state builder

* fix(copilot): update showPlanTodos logic to reflect only incomplete todos

---------

Co-authored-by: Codex <codex@openai.com>
@BWJ2310-backup BWJ2310-backup marked this pull request as ready for review June 6, 2026 22:13
@BWJ2310-backup BWJ2310-backup merged commit 78a776d into main Jun 6, 2026
5 checks passed
@BWJ2310-backup BWJ2310-backup deleted the staging branch June 6, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant