diff --git a/CHANGELOG.md b/CHANGELOG.md index 35ff02d..c33eab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ platform API version. ## [Unreleased] +**Release:** this release must bump `DIALOGRAM_API_VERSION` to 0.9 and ship +with products built against it: its API removals (#127, #129) and the stock +bundle's dropping the agent workflow UI (below) need a product still at 0.8 +to fail its version check rather than run against what it no longer has. + ### Removed - **The `@path` annotation editor and its wizard template.** No producer has @@ -96,6 +101,19 @@ platform API version. ### Changed +- **Breaking for a product that showed the agent workflow UI from the stock + bundle: it no longer loads it.** The `@tool` and `@agent` annotation + editors, the agent sections of a node's panel (Skill row, Agent Tools, live + Agent Context), the wizard's `@tool` and `@viewer` templates and the + handlers of the server's skill and agent-preset answers were wfpy's, yet + every stock-bundle product showed the editors, the header's "Add @tool" and + "Add @agent" and the templates. They are `agentUiModule`, which wfpy-ide's + own webview bundle loads (endrix/wfpy-ide#24, merged). sv, vhdl, ndf and + calpy get the plain annotation card and only the wizard's "Custom + annotation…"; none of them has `@agent` nodes, so Agent Tools, the Skill + row and Agent Context never appeared for them. The stock bundle is 141 KB + smaller. Ship in the 0.9 release (above). + - **Breaking for a profile that relied on the defaults: the Entities palette, navigation and the source MIME type are the product's.** The tool-palette provider no longer hard-codes wfpy's five rows (Task, Tool, Agent, Viewer, diff --git a/packages/diagram-client/README.md b/packages/diagram-client/README.md index 6dbf2ad..ed6cc75 100644 --- a/packages/diagram-client/README.md +++ b/packages/diagram-client/README.md @@ -208,8 +208,8 @@ Without `formatAnnotation`, Save writes `@name(key=value, ...)`. With ones the card does not show. `guiOnlyArgs` are keys your editor keeps in `args` for its own state; Save writes them nowhere. `quickAdd` puts an "add from template" button in the Annotations header. There is one editor per -name: a later binding replaces an earlier one, so your module can replace one -of the stock editors (`@tool`, `@agent`). +name: a later binding replaces an earlier one, so a module loaded later can +replace an editor an earlier one bound. **Node sections.** To show more about a node than the panel's own sections, bind a `NodeSectionContribution`. It needs an `id`; every hook is optional: @@ -241,9 +241,7 @@ export const myFeaturesModule = new ContainerModule(bind => { again, for an answer that arrives later. Contributions are asked in the order their ids were first bound. A later -binding for an id replaces the earlier one, so your module can replace the -stock bundle's agent sections (id `agent`: the Skill row, Agent Tools and the -live Agent Context). +binding for an id replaces the earlier one. **Annotation templates.** The Annotations header's "Wizard…" adds an annotation from a template, or from a name and arguments typed in. To offer a @@ -267,8 +265,14 @@ export const myFeaturesModule = new ContainerModule(bind => { There is one template per annotation name, and a later binding replaces an earlier one. The wizard lists them before its own "Custom annotation…" entry -(`custom`), which a template cannot replace. The stock bundle binds `@tool` -and `@viewer`. +(`custom`), which a template cannot replace. + +**The agent workflow UI.** The stock bundle binds no editors, sections or +templates. wfpy's are `agentUiModule`, imported by path as +`@dialogram/diagram-client/agent-ui/index`: the `@tool` and `@agent` +editors, the agent sections (id `agent`: Basic Info's Skill row, Agent Tools +and the live Agent Context) and the `@tool` and `@viewer` templates. A bundle +that wants them passes it in `features`, as wfpy-ide's does. **A diagram of your own.** When you compose the container yourself: diff --git a/packages/diagram-client/src/agent-ui/index.ts b/packages/diagram-client/src/agent-ui/index.ts index 0842349..51b2faa 100644 --- a/packages/diagram-client/src/agent-ui/index.ts +++ b/packages/diagram-client/src/agent-ui/index.ts @@ -2,16 +2,22 @@ * The agent workflow UI: the `@tool` and `@agent` annotation editors, the agent * sections of a node's panel, and the wizard's `@tool` and `@viewer` templates. * - * `agentUiModule` binds all of it. A product's own webview bundle passes it to - * `startStockDiagram({ features: [agentUiModule] })` (imported by path, - * `@dialogram/diagram-client/agent-ui/index`); the stock feature module binds - * the same today, and each contribution point keeps the last binding per - * name or id, so binding it twice draws everything once. + * `agentUiModule` binds all of it. The stock bundle does not load it: a + * product's own webview bundle passes it to + * `startStockDiagram({ features: [agentUiModule] })`, imported by path as + * `@dialogram/diagram-client/agent-ui/index`. */ import { ContainerModule, type interfaces } from 'inversify'; +import { configureActionHandler } from '@eclipse-glsp/client'; import { AnnotationEditor } from '../annotation-editor'; import { AnnotationTemplate } from '../annotation-template'; import { NodeSectionContribution } from '../node-section'; +import { + WorkflowShowAgentSkillsAction, + WorkflowShowAgentSkillsActionHandler, + WorkflowShowClaudeAgentsAction, + WorkflowShowClaudeAgentsActionHandler +} from '../editing-action-handlers'; import { AgentAnnotationEditor } from './agent-editor'; import { AgentNodeSections } from './agent-sections'; import { ToolAnnotationEditor } from './tool-editor'; @@ -19,32 +25,48 @@ import { ToolAnnotationTemplate } from './tool-template'; import { ViewerAnnotationTemplate } from './viewer-template'; /** Fresh instances, in the order the panel shows them. */ -export function stockAnnotationEditors(): AnnotationEditor[] { +export function agentUiEditors(): AnnotationEditor[] { return [new ToolAnnotationEditor(), new AgentAnnotationEditor()]; } /** A fresh instance: it keeps the chat history it last drew. */ -export function stockNodeSections(): NodeSectionContribution[] { +export function agentUiNodeSections(): NodeSectionContribution[] { return [new AgentNodeSections()]; } /** The wizard's templates, in its menu order. */ -export function stockAnnotationTemplates(): AnnotationTemplate[] { +export function agentUiTemplates(): AnnotationTemplate[] { return [new ToolAnnotationTemplate(), new ViewerAnnotationTemplate()]; } -/** Bind fresh instances of all of it into a feature module. */ -export function bindAgentUi(bind: interfaces.Bind): void { - for (const editor of stockAnnotationEditors()) { +/** What a feature module's registry is handed, as GLSP's helpers take it. */ +export interface ModuleContext { + bind: interfaces.Bind; + unbind: interfaces.Unbind; + isBound: interfaces.IsBound; + rebind: interfaces.Rebind; +} + +/** + * Bind fresh instances of all of it into a feature module, and the handlers + * of the server's answers to the `@agent` editor's discovery requests (the + * skills and agent presets it found), whose caches the editor and the Skill + * row read. + */ +export function bindAgentUi(context: ModuleContext): void { + const { bind } = context; + configureActionHandler(context, WorkflowShowAgentSkillsAction.KIND, WorkflowShowAgentSkillsActionHandler); + configureActionHandler(context, WorkflowShowClaudeAgentsAction.KIND, WorkflowShowClaudeAgentsActionHandler); + for (const editor of agentUiEditors()) { bind(AnnotationEditor).toConstantValue(editor); } - for (const sections of stockNodeSections()) { + for (const sections of agentUiNodeSections()) { bind(NodeSectionContribution).toConstantValue(sections); } - for (const template of stockAnnotationTemplates()) { + for (const template of agentUiTemplates()) { bind(AnnotationTemplate).toConstantValue(template); } } /** The agent workflow UI as a feature module of its own. */ -export const agentUiModule = new ContainerModule(bind => bindAgentUi(bind)); +export const agentUiModule = new ContainerModule((bind, unbind, isBound, rebind) => bindAgentUi({ bind, unbind, isBound, rebind })); diff --git a/packages/diagram-client/src/annotation-editor.ts b/packages/diagram-client/src/annotation-editor.ts index 314d8a1..461e478 100644 --- a/packages/diagram-client/src/annotation-editor.ts +++ b/packages/diagram-client/src/annotation-editor.ts @@ -12,8 +12,8 @@ * * and passes the module to `startStockDiagram({ features })`. There is one * editor per annotation name: a later binding for a name replaces the earlier - * one, so a product's module, which loads after the stock one, can replace a - * stock editor. The section header's quick-add buttons follow the order in + * one, so a module that loads later can replace an editor an earlier one + * bound (the stock diagram binds none). The section header's quick-add buttons follow the order in * which the names were first bound. */ import type { IActionDispatcher } from '@eclipse-glsp/client'; diff --git a/packages/diagram-client/src/annotation-template.ts b/packages/diagram-client/src/annotation-template.ts index 7fb2d42..611b199 100644 --- a/packages/diagram-client/src/annotation-template.ts +++ b/packages/diagram-client/src/annotation-template.ts @@ -10,8 +10,8 @@ * * and passes the module to `startStockDiagram({ features })`. There is one * template per annotation name: a later binding for a name replaces the - * earlier one, so a product's module, which loads after the stock one, can - * replace a stock template. The wizard lists them in the order the names were + * earlier one, so a module that loads later can replace a template an + * earlier one bound (the stock diagram binds none). The wizard lists them in the order the names were * first bound, before its own "Custom annotation…" entry; a template without a * name is ignored. */ diff --git a/packages/diagram-client/src/contributions.ts b/packages/diagram-client/src/contributions.ts index 1504ab5..9310015 100644 --- a/packages/diagram-client/src/contributions.ts +++ b/packages/diagram-client/src/contributions.ts @@ -1,8 +1,8 @@ /** * How a contribution point picks among what products bound: one per key, a - * later binding replacing an earlier one in the earlier one's place. A - * product's feature module loads after the stock one, so it can replace a - * stock contribution. An empty key drops the contribution. + * later binding replacing an earlier one in the earlier one's place, so a + * module that loads later can replace what an earlier one bound. An empty + * key drops the contribution. */ export function lastPerKey(bound: readonly T[] | undefined, keyOf: (item: T) => string): T[] { const byKey = new Map(); diff --git a/packages/diagram-client/src/node-section.ts b/packages/diagram-client/src/node-section.ts index f7bb13a..ce47d7a 100644 --- a/packages/diagram-client/src/node-section.ts +++ b/packages/diagram-client/src/node-section.ts @@ -12,8 +12,8 @@ * * and passes the module to `startStockDiagram({ features })`. There is one * contribution per `id`: a later binding for an id replaces the earlier one, so - * a product's module, which loads after the stock one, can replace a stock - * contribution. Contributions are asked in the order their ids were first + * a module that loads later can replace a contribution an earlier one bound + * (the stock diagram binds none). Contributions are asked in the order their ids were first * bound, so their rows and sections come in that order. */ import type { PropertyElement } from './property-model'; @@ -47,7 +47,7 @@ export interface NodeSectionHost { } export interface NodeSectionContribution { - /** What the contribution is, for a later binding to replace it: the stock one is `'agent'`. */ + /** What the contribution is, for a later binding to replace it (the agent sections are `'agent'`). */ readonly id: string; /** Once, when the panel starts. */ diff --git a/packages/diagram-client/src/property-panel.ts b/packages/diagram-client/src/property-panel.ts index 7491d7c..8d0e1e8 100644 --- a/packages/diagram-client/src/property-panel.ts +++ b/packages/diagram-client/src/property-panel.ts @@ -167,8 +167,8 @@ export class PropertyPanel implements ISelectionListener, IGModelRootListener { /** * One editor per annotation name, in the order the names were first bound. - * A later binding for a name replaces the earlier one, so a product's - * module, loaded after the stock one, can replace a stock editor. + * A later binding for a name replaces the earlier one, so a module that + * loads later can replace an editor an earlier one bound. */ protected annotationEditors(): readonly AnnotationEditor[] { return lastPerKey(this.contributedAnnotationEditors, editor => editor.annotationName); diff --git a/packages/diagram-client/src/stock-features.module.ts b/packages/diagram-client/src/stock-features.module.ts index f2705d8..162f52c 100644 --- a/packages/diagram-client/src/stock-features.module.ts +++ b/packages/diagram-client/src/stock-features.module.ts @@ -13,7 +13,6 @@ import { ContainerModule } from 'inversify'; import { ChangeBoundsTool, TYPES, bindAsService, configureActionHandler } from '@eclipse-glsp/client'; import { MoveAction } from '@eclipse-glsp/sprotty'; import { PropertyPanel } from './property-panel'; -import { bindAgentUi } from './agent-ui'; import { ChatPanel } from './chat-panel-integrated'; import { clientBehavior } from './profile'; import { WorkflowNavigationUi } from './navigation-ui'; @@ -49,11 +48,7 @@ import { WorkflowEditParametersAction, WorkflowEditParametersActionHandler, WorkflowEditAnnotationsAction, - WorkflowEditAnnotationsActionHandler, - WorkflowShowAgentSkillsAction, - WorkflowShowAgentSkillsActionHandler, - WorkflowShowClaudeAgentsAction, - WorkflowShowClaudeAgentsActionHandler + WorkflowEditAnnotationsActionHandler } from './editing-action-handlers'; /** @@ -67,16 +62,15 @@ export const workflowFeaturesModule = new ContainerModule((bind, unbind, isBound bind(WorkflowNavigationUi).toSelf().inSingletonScope(); // Register property panel as both selection listener and model-root listener. - // IGModelRootListener fires on every SetModelAction, enabling the panel to - // update agent context in real time even when the selection hasn't changed. + // IGModelRootListener fires on every SetModelAction, so a node section can + // update itself in place while a run streams, even when the selection + // hasn't changed (`NodeSectionContribution.modelChanged`). bind(PropertyPanel).toSelf().inSingletonScope(); bind(TYPES.ISelectionListener).toService(PropertyPanel); bind(TYPES.IGModelRootListener).toService(PropertyPanel); - // The agent workflow UI (agent-ui/): the panel's `@tool` and `@agent` - // editors, the agent sections of a node's panel (Basic Info's Skill row, - // Agent Tools, the live Agent Context) and the wizard's `@tool` and - // `@viewer` templates. A product's module binds its own the same way. - bindAgentUi(bind); + // No annotation editors, node sections or wizard templates of its own: a + // product binds those in its feature module. The agent workflow UI is + // `agentUiModule` (agent-ui/), which a product's own bundle loads. // The hierarchy outline, fed by the root model's `wf:hierarchy`. Shown only // when the product navigates nested workflows in place and the model @@ -136,8 +130,6 @@ export const workflowFeaturesModule = new ContainerModule((bind, unbind, isBound configureActionHandler(context, WorkflowOpenViewAction.KIND, WorkflowOpenViewActionHandler); configureActionHandler(context, WorkflowEditParametersAction.KIND, WorkflowEditParametersActionHandler); configureActionHandler(context, WorkflowEditAnnotationsAction.KIND, WorkflowEditAnnotationsActionHandler); - configureActionHandler(context, WorkflowShowAgentSkillsAction.KIND, WorkflowShowAgentSkillsActionHandler); - configureActionHandler(context, WorkflowShowClaudeAgentsAction.KIND, WorkflowShowClaudeAgentsActionHandler); // The profile's status source on the canvas's context menu ("Show