diff --git a/README.md b/README.md index 4797610..a44d8a7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HumainFlowGuiA21 +# HumAInFlow This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.0.3. diff --git a/src/app/app.ts b/src/app/app.ts index 61d957a..734b29d 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -12,5 +12,5 @@ import { SubflowPreviewDialogHostComponent } from '@shared/subflow-preview-dialo styleUrl: './app.css' }) export class App { - protected readonly title = signal('humainFlow-gui-a21'); + protected readonly title = signal('HumAInFlow'); } diff --git a/src/app/models/flow.ts b/src/app/models/flow.ts index b86668b..66992c3 100644 --- a/src/app/models/flow.ts +++ b/src/app/models/flow.ts @@ -42,11 +42,23 @@ export type NodeFamily = 'block' | 'container'; export type BlockTypeSchema = Record | null; +export type BlockInteractionContractKind = 'chat-session' | 'single-response' | string; + +export type BlockInteractionContract = { + kind: BlockInteractionContractKind; + messageField: string | null; + completionField: string | null; + historyField: string | null; + responseField: string | null; + supportsPartialResult: boolean; +}; + export type BlockType = { type: BlockTypeName; family: NodeFamily; description: string; userInteractive: boolean; + interactionContract?: BlockInteractionContract | null; hasExampleBlock?: boolean; exampleBlockEndpoint?: string | null; configurationType: string | null; diff --git a/src/app/models/task-execution.ts b/src/app/models/task-execution.ts index b0d22aa..7c17e22 100644 --- a/src/app/models/task-execution.ts +++ b/src/app/models/task-execution.ts @@ -44,6 +44,7 @@ export type TaskExecutionStep = { id: string; inputs: TaskExecutionStepInput[]; outputs: TaskExecutionStepOutput[]; + result?: Record; status: StepStatus; started: boolean; simulated: boolean; diff --git a/src/app/pages/main/editor-sidebar/editor-sidebar.css b/src/app/pages/main/editor-sidebar/editor-sidebar.css index edb4e2d..ba7c82c 100644 --- a/src/app/pages/main/editor-sidebar/editor-sidebar.css +++ b/src/app/pages/main/editor-sidebar/editor-sidebar.css @@ -5,7 +5,10 @@ .editor-sidebar-content { display: flex; + flex: 1 1 auto; flex-direction: column; + min-height: 0; + min-width: 0; gap: 1.5rem; } diff --git a/src/app/pages/main/editor-sidebar/editor-sidebar.html b/src/app/pages/main/editor-sidebar/editor-sidebar.html index c615218..69f7a0d 100644 --- a/src/app/pages/main/editor-sidebar/editor-sidebar.html +++ b/src/app/pages/main/editor-sidebar/editor-sidebar.html @@ -48,7 +48,7 @@
@switch (open) { @case ('flows') { -
+
@if (!creatingFlow()) { } @case ('blocks') { -
+
} @case ('containers') { -
+
diff --git a/src/app/services/blocks/blocks-call.fake.ts b/src/app/services/blocks/blocks-call.fake.ts index f526aa7..72b7cbb 100644 --- a/src/app/services/blocks/blocks-call.fake.ts +++ b/src/app/services/blocks/blocks-call.fake.ts @@ -9,6 +9,14 @@ export class BlocksCallServiceFake extends BlocksCallServiceBase { "family": "block", "description": "A block that requires human interaction", "userInteractive": true, + "interactionContract": { + "kind": "single-response", + "messageField": null, + "completionField": "output", + "historyField": null, + "responseField": "output", + "supportsPartialResult": false + }, "configurationType": "HumanInteractiveBlockConfiguration", "configurationClass": "it.cnr.isti.workflow.manager.blocks.configurations.HumanInteractiveBlockConfiguration", "schema": { diff --git a/src/app/services/blocks/blocks-call.ts b/src/app/services/blocks/blocks-call.ts index 2086330..4723ccb 100644 --- a/src/app/services/blocks/blocks-call.ts +++ b/src/app/services/blocks/blocks-call.ts @@ -91,6 +91,7 @@ export class BlocksCallService extends BlocksCallServiceBase { family: 'block', description: String(value["description"] ?? ""), userInteractive: Boolean(value["userInteractive"] ?? value["interactive"] ?? false), + interactionContract: this.toInteractionContract(value["interactionContract"]), hasExampleBlock: Boolean(value["hasExampleBlock"] ?? false), exampleBlockEndpoint: this.toApiPath(value["exampleBlockEndpoint"]), configurationType: this.toNullableString(value["configurationType"]), @@ -166,6 +167,27 @@ export class BlocksCallService extends BlocksCallServiceBase { return raw as Record; } + private toInteractionContract(raw: unknown): BlockType["interactionContract"] { + if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null; + const value = raw as Record; + const kind = typeof value["kind"] === "string" && value["kind"].trim().length > 0 + ? value["kind"].trim() + : null; + if (!kind) return null; + + const asNullableString = (input: unknown) => + typeof input === "string" && input.trim().length > 0 ? input.trim() : null; + + return { + kind, + messageField: asNullableString(value["messageField"]), + completionField: asNullableString(value["completionField"]), + historyField: asNullableString(value["historyField"]), + responseField: asNullableString(value["responseField"]), + supportsPartialResult: value["supportsPartialResult"] === true + }; + } + private toRecord(value: unknown): Record { if (!value || typeof value !== "object" || Array.isArray(value)) return {}; return value as Record; diff --git a/src/app/services/dialogs/human-interaction-dialog.ts b/src/app/services/dialogs/human-interaction-dialog.ts index 61c2038..1f3bf4a 100644 --- a/src/app/services/dialogs/human-interaction-dialog.ts +++ b/src/app/services/dialogs/human-interaction-dialog.ts @@ -1,13 +1,25 @@ import { Injectable, signal } from '@angular/core'; +import { BlockInteractionContractKind } from '@models/flow'; + +export type HumanInteractionChatMessage = { + role: 'user' | 'assistant' | 'system'; + content: string; +}; + export type HumanInteractionDialogInput = { title?: string; - actionDescription: string; - currentInput: string; + kind: BlockInteractionContractKind; + actionDescription?: string; + currentInput?: string; + history?: HumanInteractionChatMessage[]; + latestResponse?: string; + messageField?: string | null; + completionField?: string | null; }; export type HumanInteractionDialogResult = { - mode: 'confirm' | 'edit'; + mode: 'message' | 'complete'; value: string; }; @@ -15,8 +27,13 @@ export type HumanInteractionDialogResult = { export class HumanInteractionDialogService { private _state = signal<{ title: string; + kind: BlockInteractionContractKind; actionDescription: string; currentInput: string; + history: HumanInteractionChatMessage[]; + latestResponse: string; + messageField: string | null; + completionField: string | null; resolve: (value: HumanInteractionDialogResult | null) => void; } | null>(null); @@ -26,8 +43,13 @@ export class HumanInteractionDialogService { return new Promise((resolve) => { this._state.set({ title: input.title ?? 'Human interaction', - actionDescription: input.actionDescription, - currentInput: input.currentInput, + kind: input.kind, + actionDescription: input.actionDescription ?? '', + currentInput: input.currentInput ?? '', + history: input.history ?? [], + latestResponse: input.latestResponse ?? '', + messageField: input.messageField ?? null, + completionField: input.completionField ?? null, resolve }); }); diff --git a/src/app/shared/human-interaction-dialog/human-interaction-dialog.html b/src/app/shared/human-interaction-dialog/human-interaction-dialog.html index e36bb0e..2357aa9 100644 --- a/src/app/shared/human-interaction-dialog/human-interaction-dialog.html +++ b/src/app/shared/human-interaction-dialog/human-interaction-dialog.html @@ -6,11 +6,58 @@

{{ currentState.title }}

-

Confirm the input as node output or edit it before sending.

+

+ @if (currentState.kind === 'chat-session') { + Continue the chat session or send the final completion value. + } @else { + Confirm the input as node output or edit it before sending. + } +

+ @if (currentState.kind === 'chat-session') { +
+
+
+ @for (message of currentState.history; track $index) { +
+
+
{{ message.role }}
+
{{ message.content }}
+
+
+ } + + @if (!currentState.history.length) { +
No messages yet.
+ } +
+
+ +
+ + Type a message + + +
+
+ } @else {
Action Description @@ -24,11 +71,13 @@ @if (editing()) { - Edit Response + + Edit Response +