From bef1d16f0e58a2adc2feb7ae33def990e69f498e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20M=2E=20Wo=C5=BAniak?= Date: Sun, 11 Oct 2026 10:00:06 +0200 Subject: [PATCH] Update T3 contract to 8d199b4 Adds t3_workflow_stop, a runtimeModes list per provider in orchestrator_capabilities, and an inherited runtime mode that steps down to the broadest mode the target provider offers. No adapter mapping breaks, so the plugin is unchanged. --- pins.json | 2 +- .../src/mcp/toolkits/orchestrator/tools.ts | 17 ++++++++++++++++- .../packages/contracts/src/orchestratorMcp.ts | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pins.json b/pins.json index 7ac775b..554a1c0 100644 --- a/pins.json +++ b/pins.json @@ -23,7 +23,7 @@ }, "t3": { "repo": "pingdotgg/t3code", - "commit": "57b3780770a829ff81e62d8dc658683bf51d5155", + "commit": "8d199b4f7b918079161d5f43e0146c099301be08", "paths": [ "apps/server/src/mcp/toolkits/attachment/tools.ts", "apps/server/src/mcp/toolkits/device/tools.ts", diff --git a/t3/contract/apps/server/src/mcp/toolkits/orchestrator/tools.ts b/t3/contract/apps/server/src/mcp/toolkits/orchestrator/tools.ts index 33be4d2..3248618 100644 --- a/t3/contract/apps/server/src/mcp/toolkits/orchestrator/tools.ts +++ b/t3/contract/apps/server/src/mcp/toolkits/orchestrator/tools.ts @@ -1,5 +1,6 @@ import { OrchestratorMcpCapabilitiesResult, + OrchestrationV2StopWorkflowInput, OrchestratorMcpCreateThreadsInput, OrchestratorMcpCreateThreadsResult, OrchestratorMcpDelegateTaskInput, @@ -31,6 +32,7 @@ import { ThreadMetadataMcpUpdateResult, } from "@t3tools/contracts"; import { Tool, Toolkit } from "effect/ai"; +import * as Schema from "effect/Schema"; import * as ThreadManagementService from "../../../orchestration-v2/ThreadManagementService.ts"; import * as McpInvocationContext from "../../McpInvocationContext.ts"; @@ -63,7 +65,7 @@ const OrchestratorCapabilitiesTool = Tool.make("orchestrator_capabilities", { export const DelegateTaskTool = Tool.make("delegate_task", { description: - "Needs an agent running inside a T3 thread. Delegate one task to a T3-owned child agent/subagent of THIS thread and run it with only the supplied task prompt, without copying parent conversation history. Choose providers and models from orchestrator_capabilities, which uses the same live catalog as the composer. Prefer native subagent tools for same-provider work only when they support the chosen model. Use this for any model missing from the native tool, including same-provider work, for cross-provider work, or for explicitly T3-owned child tasks. For every T3 delegated review round, call delegate_task again with the original brief, prior findings, responses, and unresolved objections in the task prompt. Track each round by its own taskId and use a distinct clientRequestId per round, stable across retries of that round. The childThreadId is backing storage, not the target for starting another delegated review round through t3_thread_send. Provider, model, model options (see orchestrator_capabilities), runtime mode, and interaction mode inherit unless target overrides them. Prefer mode='async' for long work; mode='wait' blocks until completion or timeout. timeoutMs on mode=wait is only the parent's wait budget and does not cancel the child. waitTimedOut on that wait call means the timeout fired; keep that taskId and read status on later task_status. An async child's completion wakes this thread through a notification, steered into active turns where supported or queued otherwise, so end the turn instead of polling or spawning watchers; use task_status only when the result is needed mid-turn.", + "Needs an agent running inside a T3 thread. Delegate one task to a T3-owned child agent/subagent of THIS thread and run it with only the supplied task prompt, without copying parent conversation history. Choose providers and models from orchestrator_capabilities, which uses the same live catalog as the composer. Prefer native subagent tools for same-provider work only when they support the chosen model. Use this for any model missing from the native tool, including same-provider work, for cross-provider work, or for explicitly T3-owned child tasks. For every T3 delegated review round, call delegate_task again with the original brief, prior findings, responses, and unresolved objections in the task prompt. Track each round by its own taskId and use a distinct clientRequestId per round, stable across retries of that round. The childThreadId is backing storage, not the target for starting another delegated review round through t3_thread_send. Provider, model, model options (see orchestrator_capabilities), runtime mode, and interaction mode inherit unless target overrides them. A requested runtimeMode must be one the target provider lists in orchestrator_capabilities runtimeModes; an inherited one steps down to the broadest mode it offers. Prefer mode='async' for long work; mode='wait' blocks until completion or timeout. timeoutMs on mode=wait is only the parent's wait budget and does not cancel the child. waitTimedOut on that wait call means the timeout fired; keep that taskId and read status on later task_status. An async child's completion wakes this thread through a notification, steered into active turns where supported or queued otherwise, so end the turn instead of polling or spawning watchers; use task_status only when the result is needed mid-turn.", parameters: OrchestratorMcpDelegateTaskInput, success: OrchestratorMcpDelegateTaskResult, failure: OrchestratorMcpFailure, @@ -100,6 +102,18 @@ const TaskCancelTool = Tool.make("task_cancel", { .annotate(Tool.Title, "Cancel delegated task") .annotate(Tool.Destructive, true); +const WorkflowStopTool = Tool.make("t3_workflow_stop", { + description: + "Stop one running Claude workflow in a T3 thread. Use the workflow coordinator's subagentId returned by t3_thread_read with view='activity'. Stops the whole workflow, including its phases and agents. Does not stop the parent thread or other workflows. Individual workflow phases and agents cannot be stopped separately.", + parameters: OrchestrationV2StopWorkflowInput, + success: Schema.Struct({}), + failure: OrchestratorMcpFailure, + failureMode: "return", + dependencies, +}) + .annotate(Tool.Title, "Stop a workflow") + .annotate(Tool.Destructive, true); + export const ScheduleTaskTool = Tool.make("schedule_task", { description: "Create persistent work in the app scheduler that runs even when no turn is active. Pass schedule as a STRUCTURED OBJECT, never JSON text. Timers: {type:'interval', everyMs:3600000} is hourly; {type:'fixed_time', timeOfDay:'09:00', weekdays:[1,2,3,4,5]} is weekday mornings; report the returned nextRunAt. Webhooks: {type:'webhook'} runs once per request to a generated URL. The run sees the request ONLY through prompt placeholders: {{body.path}} (e.g. {{body.action}}, {{body.release.tag_name}}), {{headers.name}}, {{query.name}}, {{body}}, or {{request}} (method, headers with credentials redacted, and body). For a sender that signs requests, first call request_secret so the user enters the secret privately (never ask for it in chat or invent one), then set signature with the returned secretRef, e.g. GitHub: {type:'webhook', signature:{header:'x-hub-signature-256', encoding:'hex', prefix:'sha256=', secretRef}}. The result's webhookUrl is the public URL to give the user; if it is absent, this environment has no T3 Connect managed tunnel, so tell the user to enable T3 Connect remote access rather than sharing a path. Omit projectId for this thread's project. In this thread's project, runs post into THIS thread by default (bindToCurrentThread=true), which suits an orchestrator that sees every trigger, delegates work, and can dedupe against what is in flight; use false only when the user wants a fresh top-level thread per run. Elsewhere each run launches a fresh thread. Provider, model, and runtime settings inherit from this thread, or from the project default when there is no calling thread.", @@ -261,6 +275,7 @@ export const OrchestratorToolkit = Toolkit.make( DelegateTaskTool, TaskStatusTool, TaskCancelTool, + WorkflowStopTool, ScheduleTaskTool, ListScheduledTasksTool, UpdateScheduledTaskTool, diff --git a/t3/contract/packages/contracts/src/orchestratorMcp.ts b/t3/contract/packages/contracts/src/orchestratorMcp.ts index f0ffa07..0738426 100644 --- a/t3/contract/packages/contracts/src/orchestratorMcp.ts +++ b/t3/contract/packages/contracts/src/orchestratorMcp.ts @@ -399,6 +399,7 @@ export const OrchestratorMcpThreadTimelineItem = Schema.Struct({ visibility: Schema.Literals(["local", "inherited", "synthetic"]), sourceThreadId: ThreadId, itemId: TurnItemId, + subagentId: Schema.optional(NodeId), runId: Schema.NullOr(RunId), messageId: Schema.NullOr(MessageId), createdBy: Schema.NullOr(OrchestrationV2Actor), @@ -487,6 +488,8 @@ export const OrchestratorMcpProviderCapability = Schema.Struct({ options: Schema.optional(Schema.Array(ProviderOptionDescriptor)), }), ), + /** Runtime modes the provider offers; omitted when it offers all of them. */ + runtimeModes: Schema.optional(Schema.Array(RuntimeMode)), canRunChildTask: Schema.Boolean, canRunCrossProviderChildTask: Schema.Boolean, constraints: Schema.Array(Schema.String),