@oomol-lab/open-flow 0.1.0-beta.75 → 0.1.0-beta.77
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.
- package/README.md +3 -1
- package/dist/browser/{ContentIcon-FCpKiwjp.js → ContentIcon-VZQO8VZU.js} +9 -6
- package/dist/browser/{FlowCanvas-dzRBnlUT.js → FlowCanvas-BNGDMaWr.js} +75 -63
- package/dist/browser/{createResourceDialog-BeYDdUl-.js → createResourceDialog-BmtakfVg.js} +63 -57
- package/dist/browser/{dialog-ZtpsFbl4.js → dialog-BcFBfRB1.js} +126 -32
- package/dist/browser/{exportSvg-DqXw1yf-.js → exportSvg-CG8hEUNk.js} +2 -2
- package/dist/browser/{flowChanges-b_5UobFj.js → flowChanges-BGo_4Ypo.js} +6063 -11285
- package/dist/browser/{flowWorkspace-ItojZbO4.js → flowWorkspace-BFHGev7s.js} +1065 -2570
- package/dist/browser/preview.css +626 -653
- package/dist/browser/preview.js +1907 -9663
- package/dist/browser/theme.css +117 -263
- package/dist/browser/{tooltip-wZJRB9oP.js → tooltip-BAWSUexx.js} +2 -2
- package/dist/browser/{typeScriptSession-CSRwWmZm.js → typeScriptSession-CRoezJPN.js} +1 -1
- package/dist/browser/ui.css +464 -463
- package/dist/browser/ui.js +4 -3
- package/dist/browser/workbench.css +9891 -9897
- package/dist/browser/workbench.d.ts +6 -2
- package/dist/browser/workbench.js +838 -499
- package/dist/browser/{workbenchSelect-M441Lz0d.js → workbenchSelect-CjK-xdm3.js} +2 -2
- package/dist/command/index.js +48 -50
- package/dist/common/authoring.d.ts +5 -5
- package/dist/common/authoringExamples.d.ts +3 -2
- package/dist/common/authoringSchema.d.ts +26 -4
- package/dist/common/connector-proxy.d.ts +1 -1
- package/dist/common/control-api-conformance.js +352 -144
- package/dist/common/control-api-errors.d.ts +12 -0
- package/dist/common/control-api.d.ts +38 -4
- package/dist/common/control-api.js +373 -162
- package/dist/common/control-requests.d.ts +22 -3
- package/dist/common/control-requests.js +268 -28
- package/dist/common/cron-trigger.d.ts +2 -1
- package/dist/common/decision.d.ts +4 -4
- package/dist/common/decision.js +5 -2
- package/dist/common/engine-contract.d.ts +6 -1
- package/dist/common/event-source-definition.d.ts +1 -1
- package/dist/common/event-source-view.d.ts +22 -0
- package/dist/common/event-source.d.ts +1 -1
- package/dist/common/event-source.js +24 -65
- package/dist/common/event-sources.d.ts +0 -21
- package/dist/common/flow-authoring.js +90 -20
- package/dist/common/flow-change-schema.d.ts +9 -1
- package/dist/common/flow-change.d.ts +8 -202
- package/dist/common/flow-change.js +96 -24
- package/dist/common/flow-encoding.js +89 -21
- package/dist/common/flow-input-value.d.ts +1 -1
- package/dist/common/flow-model.d.ts +121 -0
- package/dist/common/flow-notifications.d.ts +1 -1
- package/dist/common/flow-retry.d.ts +2 -4
- package/dist/common/flow-semantics.js +161 -80
- package/dist/common/flow-state.d.ts +123 -0
- package/dist/common/flow-state.js +5852 -0
- package/dist/common/flow-workflowReferences.d.ts +8 -0
- package/dist/common/flowInspection.d.ts +1 -1
- package/dist/common/http-hosts.d.ts +6 -0
- package/dist/common/http-request.d.ts +13 -5
- package/dist/common/http-request.js +23 -5
- package/dist/common/integration-trigger.d.ts +2 -1
- package/dist/common/mcp.d.ts +96 -3
- package/dist/common/mcp.js +355 -142
- package/dist/common/openapi.d.ts +4 -4
- package/dist/common/openapi.js +4 -1
- package/dist/common/poll-trigger.d.ts +2 -1
- package/dist/common/run-events.js +1 -0
- package/dist/common/runtime-contract.d.ts +37 -1
- package/dist/common/runtime-contract.js +717 -72
- package/dist/common/runtime-nodejs-compat.d.ts +44 -0
- package/dist/common/runtime-nodejs-compat.js +5870 -0
- package/dist/common/scheduler-checkpoint.d.ts +1 -1
- package/dist/common/scheduler-node-execution.d.ts +2 -1
- package/dist/common/scheduler.d.ts +2 -2
- package/dist/common/scheduler.js +76 -6
- package/dist/common/state-conformance.d.ts +16 -0
- package/dist/common/tags.d.ts +4 -0
- package/dist/common/trigger-catalog.d.ts +1 -7
- package/dist/common/trigger-config-options.d.ts +1 -1
- package/dist/common/trigger-config.d.ts +1 -1
- package/dist/common/trigger-contract.d.ts +2 -1
- package/dist/common/trigger-localization.d.ts +8 -2
- package/dist/common/trigger-model.d.ts +101 -0
- package/dist/common/webhook-response.d.ts +1 -1
- package/dist/common/webhook-trigger.d.ts +3 -1
- package/dist/common/workflow.d.ts +3 -12
- package/dist/common/workflow.js +25 -23
- package/dist/index.d.ts +52 -14
- package/package.json +9 -1
- package/src/base/common/json.ts +1 -1
- package/src/connector/common/proxy.ts +1 -1
- package/src/control/common/api.ts +90 -16
- package/src/control/common/authoring.ts +6 -1
- package/src/control/common/authoringExamples.ts +8 -0
- package/src/control/common/authoringSchema.ts +26 -13
- package/src/control/common/authoringTools.ts +1 -1
- package/src/control/common/conformance.ts +1 -1
- package/src/control/common/connectorDecoders.ts +1 -1
- package/src/control/common/errors.ts +6 -0
- package/src/control/common/eventSources.ts +2 -29
- package/src/control/common/flowDecoders.ts +1 -0
- package/src/control/common/mcp.ts +16 -0
- package/src/control/common/requests.ts +10 -2
- package/src/control/common/tags.ts +20 -0
- package/src/control/common/triggerCatalog.ts +1 -8
- package/src/decision/common/decision.ts +15 -7
- package/src/event-source/common/definition.ts +1 -1
- package/src/event-source/common/index.ts +1 -1
- package/src/event-source/common/view.ts +20 -0
- package/src/execution/common/checkpoint.ts +1 -1
- package/src/execution/common/events.ts +3 -0
- package/src/execution/common/node-execution.ts +4 -1
- package/src/execution/common/scheduler.ts +3 -1
- package/src/flow/common/change.ts +60 -193
- package/src/flow/common/changeSchema.ts +39 -4
- package/src/flow/common/connectionUsage.ts +1 -1
- package/src/flow/common/errorHandling.ts +1 -1
- package/src/flow/common/inputValue.ts +1 -1
- package/src/flow/common/model.ts +130 -0
- package/src/flow/common/modules.ts +1 -1
- package/src/flow/common/portChanges.ts +1 -1
- package/src/flow/common/retry.ts +2 -4
- package/src/flow/common/semantics.ts +31 -4
- package/src/flow/common/webhookResponse.ts +1 -1
- package/src/flow/common/workflowReferences.ts +31 -0
- package/src/http/common/authBindings.ts +6 -9
- package/src/http/common/hosts.ts +13 -0
- package/src/http/common/httpRequest.ts +30 -15
- package/src/openapi/common/openapi.ts +9 -5
- package/src/{execution → runtime}/common/engineContract.ts +23 -15
- package/src/runtime/common/nodejsCompat.ts +275 -0
- package/src/runtime/common/nodejsGuest.generated.json +47 -0
- package/src/runtime/common/runtime.ts +1254 -0
- package/src/state/common/conformance.ts +86 -0
- package/src/state/common/state.ts +169 -0
- package/src/trigger/common/config.ts +1 -1
- package/src/trigger/common/configOptions.ts +1 -1
- package/src/trigger/common/contract.ts +2 -1
- package/src/trigger/common/cron.ts +2 -1
- package/src/trigger/common/integration.ts +2 -1
- package/src/trigger/common/model.ts +87 -0
- package/src/trigger/common/poll.ts +2 -1
- package/src/trigger/common/webhook.ts +3 -1
- package/src/trigger/providers/fieldDescriptions.ts +1 -1
- package/src/trigger/providers/localization.ts +9 -2
- package/src/trigger/providers/remote.ts +1 -1
- package/src/types/index.ts +55 -15
- package/src/workflow/common/workflow.ts +3 -44
- package/src/execution/common/runtime.ts +0 -563
- /package/src/{control → connector}/common/providerIconSprite.ts +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { CanvasCommand } from '../../canvas/common/commands.ts'
|
|
2
|
+
import type { FlowStateView, StateScope } from '../../state/common/state.ts'
|
|
2
3
|
|
|
3
|
-
import { currentEngineContract } from '../../
|
|
4
|
+
import { currentEngineContract } from '../../runtime/common/engineContract.ts'
|
|
5
|
+
import { flowStateViewSchema } from '../../state/common/state.ts'
|
|
4
6
|
import { workflowContractSchema, workflowReferencesSchema } from '../../workflow/common/workflow.ts'
|
|
5
7
|
export type { CanvasCommand, CanvasCommandSubscriber } from '../../canvas/common/commands.ts'
|
|
6
8
|
import type { LiveDetails } from './liveDetails.ts'
|
|
@@ -9,12 +11,12 @@ import { decodeLiveDetails } from './liveDetails.ts'
|
|
|
9
11
|
export { liveEntries } from './liveDetails.ts'
|
|
10
12
|
export { flowInputDefinitions } from './authoringFields.ts'
|
|
11
13
|
export type { LiveDetails, LiveEntry } from './liveDetails.ts'
|
|
14
|
+
import type { ProviderIconAppearance } from '../../connector/common/providerIconSprite.ts'
|
|
12
15
|
import type { AuthoringRead, AuthoringSearch, AuthoringRequest, AuthoringType } from './authoringSchema.ts'
|
|
13
|
-
import type { ProviderIconAppearance } from './providerIconSprite.ts'
|
|
14
16
|
|
|
15
17
|
import { authoringReadResponse, authoringSearchResponse, authoringEditResponse, authoringCheckResponse } from './authoringSchema.ts'
|
|
16
|
-
export { providerIconAppearance } from '
|
|
17
|
-
export type { ProviderIconAppearance, ProviderIconSprite, ProviderIconSpriteCatalog } from '
|
|
18
|
+
export { providerIconAppearance } from '../../connector/common/providerIconSprite.ts'
|
|
19
|
+
export type { ProviderIconAppearance, ProviderIconSprite, ProviderIconSpriteCatalog } from '../../connector/common/providerIconSprite.ts'
|
|
18
20
|
export { connectorAccess as decodeConnectorAccess, connectorAccessSnapshot as decodeConnectorAccessSnapshot } from './connectorDecoders.ts'
|
|
19
21
|
import type { ProviderAccessIdentity, ProviderAccessReference } from './providerAccess.ts'
|
|
20
22
|
export {
|
|
@@ -35,7 +37,8 @@ export { decodeEventSource, decodeEventSources, type CreateEventSource, type Upd
|
|
|
35
37
|
import type { TriggerCatalogCache } from './triggerCatalog.ts'
|
|
36
38
|
|
|
37
39
|
import { decodeTriggerCatalog } from './triggerCatalog.ts'
|
|
38
|
-
export { decodeTriggerCatalog, searchTriggerKeys, type TriggerCatalog, type TriggerCatalogCache
|
|
40
|
+
export { decodeTriggerCatalog, searchTriggerKeys, type TriggerCatalog, type TriggerCatalogCache } from './triggerCatalog.ts'
|
|
41
|
+
export type { TriggerDisplay } from '../../trigger/providers/localization.ts'
|
|
39
42
|
import type { TriggerConfigOption } from '../../trigger/common/configOptions.ts'
|
|
40
43
|
export type { TriggerConfigOption } from '../../trigger/common/configOptions.ts'
|
|
41
44
|
import type { ResultQuery } from './results.ts'
|
|
@@ -76,6 +79,8 @@ export type { FlowCatalogEvent, FlowChangeEvent } from './flowNotifications.ts'
|
|
|
76
79
|
|
|
77
80
|
import { ApiError } from './errors.ts'
|
|
78
81
|
import { randomId } from './random.ts'
|
|
82
|
+
import { decodeTag, decodeTagListItem, normalizeFlowQuery } from './tags.ts'
|
|
83
|
+
export { normalizeFlowQuery } from './tags.ts'
|
|
79
84
|
|
|
80
85
|
export interface CanvasBroadcast {
|
|
81
86
|
readonly version: 1
|
|
@@ -102,7 +107,29 @@ export interface FlowResources {
|
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
export interface FlowUpdate {
|
|
111
|
+
readonly name?: string
|
|
112
|
+
readonly tagIds?: readonly string[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface FlowQuery {
|
|
116
|
+
readonly query?: string
|
|
117
|
+
readonly tagIds?: readonly string[]
|
|
118
|
+
readonly untagged?: boolean
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface Tag {
|
|
122
|
+
readonly tagId: string
|
|
123
|
+
readonly name: string
|
|
124
|
+
readonly version: 1
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface TagListItem extends Tag {
|
|
128
|
+
readonly referenceCount: number
|
|
129
|
+
}
|
|
130
|
+
|
|
105
131
|
export interface Flow {
|
|
132
|
+
readonly tagIds?: readonly string[]
|
|
106
133
|
readonly live?: { readonly enabled: boolean; readonly hasStart: boolean; readonly publicationId: string; readonly revisionId: string }
|
|
107
134
|
|
|
108
135
|
readonly createdAt: string
|
|
@@ -676,6 +703,7 @@ export function decodeRunEvent(value: unknown) {
|
|
|
676
703
|
nodeKind !== 'decision' &&
|
|
677
704
|
nodeKind !== 'openapi' &&
|
|
678
705
|
nodeKind !== 'http-request' &&
|
|
706
|
+
nodeKind !== 'dedupe' &&
|
|
679
707
|
nodeKind !== 'llm' &&
|
|
680
708
|
nodeKind !== 'agent' &&
|
|
681
709
|
nodeKind !== 'value' &&
|
|
@@ -808,9 +836,13 @@ export class ControlClient {
|
|
|
808
836
|
}
|
|
809
837
|
|
|
810
838
|
async listFlows(
|
|
811
|
-
options: { readonly cursor?: string; readonly includeTotal?: boolean; readonly limit?: number; readonly signal?: AbortSignal } = {},
|
|
839
|
+
options: FlowQuery & { readonly cursor?: string; readonly includeTotal?: boolean; readonly limit?: number; readonly signal?: AbortSignal } = {},
|
|
812
840
|
): Promise<FlowPage> {
|
|
813
841
|
const parameters = new URLSearchParams()
|
|
842
|
+
const filter = normalizeFlowQuery(options)
|
|
843
|
+
if (filter.query) parameters.set('query', filter.query)
|
|
844
|
+
if (filter.tagIds.length) parameters.set('tagIds', filter.tagIds.join(','))
|
|
845
|
+
if (filter.untagged) parameters.set('untagged', 'true')
|
|
814
846
|
if (options.cursor != null) parameters.set('cursor', options.cursor)
|
|
815
847
|
if (options.limit != null) parameters.set('limit', String(options.limit))
|
|
816
848
|
if (options.includeTotal != null) parameters.set('includeTotal', String(options.includeTotal))
|
|
@@ -896,20 +928,23 @@ export class ControlClient {
|
|
|
896
928
|
}
|
|
897
929
|
}
|
|
898
930
|
|
|
899
|
-
async importFlow(
|
|
931
|
+
async importFlow(
|
|
932
|
+
file: WorkflowFile,
|
|
933
|
+
options: { readonly name?: string; readonly teamId?: string; readonly idempotencyKey?: string; readonly tagIds?: readonly string[] } = {},
|
|
934
|
+
): Promise<Flow> {
|
|
900
935
|
return flow(
|
|
901
936
|
await this.request('/v1/flows/import', {
|
|
902
937
|
method: 'POST',
|
|
903
938
|
headers: { 'Idempotency-Key': options.idempotencyKey ?? `flow-${randomId()}` },
|
|
904
|
-
body: JSON.stringify({ file, name: options.name, teamId: options.teamId, version: 1 }),
|
|
939
|
+
body: JSON.stringify({ file, name: options.name, teamId: options.teamId, tagIds: options.tagIds, version: 1 }),
|
|
905
940
|
}),
|
|
906
941
|
)
|
|
907
942
|
}
|
|
908
943
|
|
|
909
|
-
async createFlow(name: string, idempotencyKey = `flow-${randomId()}`, teamId?: string): Promise<Flow> {
|
|
944
|
+
async createFlow(name: string, idempotencyKey = `flow-${randomId()}`, teamId?: string, tagIds?: readonly string[]): Promise<Flow> {
|
|
910
945
|
return flow(
|
|
911
946
|
await this.request('/v1/flows', {
|
|
912
|
-
body: JSON.stringify({ name, ...(teamId == null ? {} : { teamId }), version: 1 }),
|
|
947
|
+
body: JSON.stringify({ name, ...(teamId == null ? {} : { teamId }), ...(tagIds == null ? {} : { tagIds }), version: 1 }),
|
|
913
948
|
headers: { 'idempotency-key': idempotencyKey },
|
|
914
949
|
method: 'POST',
|
|
915
950
|
}),
|
|
@@ -938,13 +973,52 @@ export class ControlClient {
|
|
|
938
973
|
return source.listeners.map(errorListener)
|
|
939
974
|
}
|
|
940
975
|
|
|
941
|
-
async
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
976
|
+
async listTags(signal?: AbortSignal): Promise<{ readonly tags: readonly TagListItem[]; readonly version: 1 }> {
|
|
977
|
+
const source = record(await this.request('/v1/tags', { signal }))
|
|
978
|
+
if (source.version != 1 || !Array.isArray(source.tags)) return invalidResponse()
|
|
979
|
+
return { tags: source.tags.map(decodeTagListItem), version: 1 }
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
async createTag(name: string): Promise<Tag> {
|
|
983
|
+
return decodeTag(await this.request('/v1/tags', { method: 'POST', body: JSON.stringify({ name, version: 1 }) }))
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
async renameTag(tagId: string, name: string): Promise<Tag> {
|
|
987
|
+
return decodeTag(await this.request(`/v1/tags/${segment(tagId)}`, { method: 'PATCH', body: JSON.stringify({ name, version: 1 }) }))
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
async deleteTag(tagId: string): Promise<void> {
|
|
991
|
+
const source = record(await this.request(`/v1/tags/${segment(tagId)}`, { method: 'DELETE' }))
|
|
992
|
+
if (source.version != 1) invalidResponse()
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
async setFlowTags(flowId: string, tagIds: readonly string[]): Promise<Flow> {
|
|
996
|
+
return flow(await this.request(`/v1/flows/${segment(flowId)}/tags`, { method: 'PUT', body: JSON.stringify({ tagIds, version: 1 }) }))
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
async updateFlow(flowId: string, changes: FlowUpdate): Promise<Flow> {
|
|
1000
|
+
return flow(await this.request(`/v1/flows/${segment(flowId)}`, { method: 'PATCH', body: JSON.stringify({ ...changes, version: 1 }) }))
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
async getFlowState(flowId: string, scope: StateScope, values = false): Promise<FlowStateView> {
|
|
1004
|
+
const result = flowStateViewSchema.safeParse(await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}&values=${values}`))
|
|
1005
|
+
return result.success && result.data.scope === scope ? result.data : invalidResponse()
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
async clearFlowState(flowId: string, scope: StateScope, key?: string): Promise<void> {
|
|
1009
|
+
const source = record(
|
|
1010
|
+
await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}${key == null ? '' : `&key=${encodeURIComponent(key)}`}`, { method: 'DELETE' }),
|
|
947
1011
|
)
|
|
1012
|
+
if (source.version !== 1 || source.cleared !== true) invalidResponse()
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
async clearFlowDedupe(flowId: string, scope: StateScope, space: string): Promise<void> {
|
|
1016
|
+
const source = record(await this.request(`/v1/flows/${segment(flowId)}/dedupe?scope=${scope}&space=${encodeURIComponent(space)}`, { method: 'DELETE' }))
|
|
1017
|
+
if (source.version !== 1 || source.cleared !== true) invalidResponse()
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
async renameFlow(flowId: string, name: string): Promise<Flow> {
|
|
1021
|
+
return this.updateFlow(flowId, { name })
|
|
948
1022
|
}
|
|
949
1023
|
|
|
950
1024
|
async deleteFlow(flowId: string): Promise<Flow> {
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
} from '../../flow/common/nodeChanges.ts'
|
|
44
44
|
import { retryConfigurationSchema } from '../../flow/common/retry.ts'
|
|
45
45
|
import { httpRequestTask, httpRequestConfigSchema, httpRequestInputs } from '../../http/common/httpRequest.ts'
|
|
46
|
+
import { dedupeConfigSchema, dedupeTask } from '../../state/common/state.ts'
|
|
46
47
|
import { withWorkflowTask, workflowTask, workflowSelectionTask, workflowCapability, workflowAgentTool } from '../../workflow/common/workflow.ts'
|
|
47
48
|
import { conditionConfigurationView, prepareConditionConfiguration } from './authoringCondition.ts'
|
|
48
49
|
import { authoringDiagnosticField } from './authoringDiagnosticFields.ts'
|
|
@@ -146,7 +147,7 @@ export function authoringNode(content: RevisionContent, ref: string) {
|
|
|
146
147
|
),
|
|
147
148
|
}
|
|
148
149
|
else if (task.executor.kind == 'workflow') config = { flowId: task.executor.flowId }
|
|
149
|
-
else if (task.executor.kind == 'http-request') {
|
|
150
|
+
else if (task.executor.kind == 'http-request' || task.executor.kind == 'dedupe') {
|
|
150
151
|
const { kind: _kind, ...settings } = task.executor
|
|
151
152
|
config = settings
|
|
152
153
|
} else if (task.executor.kind == 'openapi') {
|
|
@@ -521,6 +522,7 @@ export async function compileAuthoring(base: RevisionContent, request: Authoring
|
|
|
521
522
|
task = { ...before, name: String(update.name), executor: { ...executor, ...config } } as ManagedTaskDefinition
|
|
522
523
|
} else task = await connectorTask(config, String(update.name))
|
|
523
524
|
} else if (type == 'decision') task = decisionTask(config.questions as Parameters<typeof decisionTask>[0], String(update.name))
|
|
525
|
+
else if (type == 'dedupe') task = { ...before, name: String(update.name), executor: { kind: 'dedupe', ...dedupeConfigSchema.parse(config) } }
|
|
524
526
|
else if (type == 'http-request') {
|
|
525
527
|
task = httpRequestTask(httpRequestConfigSchema.parse(config), String(update.name), before)
|
|
526
528
|
next = { ...next, inputs: httpRequestInputs(node.inputs, before, task) } as GraphNode
|
|
@@ -774,6 +776,9 @@ export async function compileAuthoring(base: RevisionContent, request: Authoring
|
|
|
774
776
|
case 'connector':
|
|
775
777
|
changes = createManagedTask(identity, await connectorTask(config, name))
|
|
776
778
|
break
|
|
779
|
+
case 'dedupe':
|
|
780
|
+
changes = createManagedTask(identity, dedupeTask(dedupeConfigSchema.parse(config), name))
|
|
781
|
+
break
|
|
777
782
|
case 'http-request':
|
|
778
783
|
changes = createManagedTask(identity, httpRequestTask(httpRequestConfigSchema.parse(config), name))
|
|
779
784
|
break
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '../../flow/common/nodeChanges.ts'
|
|
14
14
|
import { httpRequestTask } from '../../http/common/httpRequest.ts'
|
|
15
15
|
import { openApiTask, selectOperation } from '../../openapi/common/openapi.ts'
|
|
16
|
+
import { dedupeTask } from '../../state/common/state.ts'
|
|
16
17
|
|
|
17
18
|
const descriptions = {
|
|
18
19
|
'start': 'A Start node with a required message parameter. Supply it through trigger.outputs.',
|
|
@@ -23,6 +24,7 @@ const descriptions = {
|
|
|
23
24
|
'poll': 'Gmail polling by key; replace CONNECTION_ID with an active Gmail connection.',
|
|
24
25
|
'integration': 'Telegram webhook integration by key; replace CONNECTION_ID with an active Telegram connection.',
|
|
25
26
|
'decision': 'AI Decision evaluates named questions against target and returns a complete answer object per output. Configure target before running.',
|
|
27
|
+
'dedupe': 'Filter items using persistent history. Records immediately, including when downstream work fails. Empty field uses each scalar item as identity.',
|
|
26
28
|
'http-request': 'A single HTTP request. Bind url and request inputs; outputs are body, statusCode and headers.',
|
|
27
29
|
'openapi': 'A fixed JSON API operation. Replace the example document and URL before running.',
|
|
28
30
|
'connector':
|
|
@@ -57,6 +59,12 @@ export function authoringExample(name: string): { version: 1; operations: readon
|
|
|
57
59
|
{ name: 'needs_support', type: 'noul', instructions: 'Does the customer need support?' },
|
|
58
60
|
])
|
|
59
61
|
break
|
|
62
|
+
case 'dedupe':
|
|
63
|
+
operations = [
|
|
64
|
+
...createManagedTask({ nodeId: 'dedupe' }, dedupeTask()),
|
|
65
|
+
{ kind: 'graph.node.input.set', nodeId: 'dedupe', handle: 'items', value: { kind: 'value', value: ['a', 'b', 'a'] } },
|
|
66
|
+
]
|
|
67
|
+
break
|
|
60
68
|
case 'http-request':
|
|
61
69
|
operations = [
|
|
62
70
|
...createManagedTask({ nodeId: 'http' }, httpRequestTask()),
|
|
@@ -6,10 +6,13 @@ import {
|
|
|
6
6
|
connectorAgentToolSchema,
|
|
7
7
|
workflowAgentToolSchema,
|
|
8
8
|
connectorCapabilitySchema,
|
|
9
|
+
httpCapabilitySchema,
|
|
9
10
|
authoringDefinitionSchemas as definitions,
|
|
10
11
|
} from '../../flow/common/changeSchema.ts'
|
|
11
12
|
import { retryConfigurationSchema, retryNodeTypes } from '../../flow/common/retry.ts'
|
|
12
13
|
import { httpRequestConfigSchema } from '../../http/common/httpRequest.ts'
|
|
14
|
+
import { currentEngineContract, findEngineContract } from '../../runtime/common/engineContract.ts'
|
|
15
|
+
import { dedupeConfigSchema } from '../../state/common/state.ts'
|
|
13
16
|
import { authoringLlmConfiguration } from './authoringLlm.ts'
|
|
14
17
|
import { authoringOpenApiSchema } from './authoringOpenApi.ts'
|
|
15
18
|
|
|
@@ -33,6 +36,7 @@ export const authoringTypes = [
|
|
|
33
36
|
'decision',
|
|
34
37
|
'openapi',
|
|
35
38
|
'http-request',
|
|
39
|
+
'dedupe',
|
|
36
40
|
'condition',
|
|
37
41
|
'value',
|
|
38
42
|
'wait',
|
|
@@ -71,7 +75,9 @@ const agentTool = z.union([
|
|
|
71
75
|
workflowAgentToolSchema.omit({ id: true, inputs: true, outputs: true, revisionId: true }).extend({ inputs: toolSources }).strict(),
|
|
72
76
|
connectorAgentToolSchema.omit({ id: true, inputs: true }).extend({ inputs: toolSources }).strict(),
|
|
73
77
|
])
|
|
74
|
-
const authoringCapabilities = z.array(
|
|
78
|
+
const authoringCapabilities = z.array(
|
|
79
|
+
z.union([connectorCapabilitySchema, z.strictObject({ kind: z.literal('workflow'), name: id, flowId: id }), httpCapabilitySchema]),
|
|
80
|
+
)
|
|
75
81
|
const notification = z.strictObject({
|
|
76
82
|
...definitions.connector.shape,
|
|
77
83
|
messageHandle: id,
|
|
@@ -114,6 +120,7 @@ export const authoringConfigurations = {
|
|
|
114
120
|
'connector': definitions.connector.omit({ outputMode: true }).strict(),
|
|
115
121
|
'openapi': authoringOpenApiSchema,
|
|
116
122
|
'http-request': httpRequestConfigSchema,
|
|
123
|
+
'dedupe': dedupeConfigSchema,
|
|
117
124
|
'agent': definitions.agent
|
|
118
125
|
.omit({ prompt: true, tools: true })
|
|
119
126
|
.extend({
|
|
@@ -259,6 +266,9 @@ const requestContracts = {
|
|
|
259
266
|
},
|
|
260
267
|
}
|
|
261
268
|
|
|
269
|
+
const codeBuiltins = [...findEngineContract(currentEngineContract)!.builtinModules!].filter((name) => !name.startsWith('node:'))
|
|
270
|
+
const codeGuidance = `Code is an ES module whose default export receives (inputs, context) and returns the business outputs. It may import the Node builtins ${codeBuiltins.join(', ')}, with or without the node: prefix; fs is a fresh in-memory filesystem containing /tmp per execution. require, dynamic import, packages and the http/net builtins are unavailable. To call HTTP APIs, declare their hosts in config.capabilities as {kind: "http", hosts: ["api.example.com", "*.example.org"]} and use context.fetch(url, {method, headers, body}); it returns status, ok, headers.get(), text(), json() and bytes(), does not follow redirects, adds no credentials, and limits bodies to 1 MiB. Prefer an HTTP Request node for a single call without transformation and Connector Actions for services with accounts. context provides inputs, signal, getPrevious(), fetch, actions, workflows, artifact, flowId, runId and blockId. Select workflows through config.capabilities: [{kind: "workflow", flowId, name}]. Call context.workflows.call(name, input) and await its business output. The platform derives input/output types. Refresh a selected workflow tool with node.refresh and tool: its name. Calls obey node and Run time limits.`
|
|
271
|
+
|
|
262
272
|
/** Transport-independent discovery of the same requests the service validates. */
|
|
263
273
|
export function authoringRequestContract(name: string) {
|
|
264
274
|
if (!Object.hasOwn(requestContracts, name)) return undefined
|
|
@@ -276,7 +286,7 @@ export function authoringSchema(kind?: AuthoringType) {
|
|
|
276
286
|
}
|
|
277
287
|
: {
|
|
278
288
|
type: kind,
|
|
279
|
-
onError: retryNodeTypes.some((nodeType) => nodeType == kind) ? { enum: ['stop', 'error'] } : false,
|
|
289
|
+
onError: kind == 'dedupe' || retryNodeTypes.some((nodeType) => nodeType == kind) ? { enum: ['stop', 'error'] } : false,
|
|
280
290
|
retry: retryNodeTypes.some((nodeType) => nodeType == kind) ? z.toJSONSchema(retryConfigurationSchema) : false,
|
|
281
291
|
inputSources: ['poll', 'integration'].includes(kind)
|
|
282
292
|
? ['value', 'unset', 'default']
|
|
@@ -299,17 +309,19 @@ export function authoringSchema(kind?: AuthoringType) {
|
|
|
299
309
|
? 'Configure static parameters with node.add.inputs or input.set. Definitions come from the selected Trigger key; execution output and variable sources are unavailable.'
|
|
300
310
|
: kind == 'llm'
|
|
301
311
|
? 'Configure model settings, message templates and history as defaults. Input bindings with the same names override these defaults; named business inputs can be bound directly. Template strings interpolate {{name}}.'
|
|
302
|
-
: kind == '
|
|
303
|
-
? 'Configure
|
|
304
|
-
: kind == '
|
|
305
|
-
? '
|
|
306
|
-
: kind == '
|
|
307
|
-
? 'Select
|
|
308
|
-
: kind == '
|
|
309
|
-
? '
|
|
310
|
-
: kind == '
|
|
311
|
-
? '
|
|
312
|
-
:
|
|
312
|
+
: kind == 'dedupe'
|
|
313
|
+
? 'Bind an items array. Configure field (dot-separated identity path, empty for scalar items), mode (new or increasing), and space (node or flow). Outputs are items and duplicates. History persists immediately; downstream failures do not roll it back. Increasing mode accepts finite numbers or RFC 3339 timestamps, never mixed types.'
|
|
314
|
+
: kind == 'http-request'
|
|
315
|
+
? 'Configure method, query/headers modes and names, bodyFormat, authentication, responseFormat and statusPolicy. Bind url, query.<name>/header.<name> or whole query/headers objects, body and auth.token (Basic: auth.username/auth.password). Credentials accept variables or upstream outputs only. Outputs: body, statusCode, headers. Authentication is replaced as a complete choice.'
|
|
316
|
+
: kind == 'openapi'
|
|
317
|
+
? 'Select an operation; the tool resolves its ports and authentication. Read authenticationChoices from node details. authentication is replaced as a complete choice. Bind advertised credentials through inputs.'
|
|
318
|
+
: kind == 'workflow'
|
|
319
|
+
? 'Select another workflow with config.flowId. A workflow cannot call itself, including in a disconnected node. Owned unpublished or unavailable targets may be saved as incomplete drafts. Use node.refresh to load the current published interface.'
|
|
320
|
+
: kind == 'agent'
|
|
321
|
+
? 'Tools accept Connector Actions or {kind: "workflow", flowId, name, description, approval, inputs}. Workflow parameter sources use model, input or value. The platform derives the interface. Refresh a workflow tool with node.refresh and tool: its name.'
|
|
322
|
+
: kind == 'code'
|
|
323
|
+
? codeGuidance
|
|
324
|
+
: 'Supply business configuration and input data. Fixed definitions are assembled by the tool. Existing constraints and defaults are preserved on partial updates.',
|
|
313
325
|
example: {
|
|
314
326
|
op: 'node.add',
|
|
315
327
|
as: 'step',
|
|
@@ -323,6 +335,7 @@ export function authoringSchema(kind?: AuthoringType) {
|
|
|
323
335
|
'connector': { config: { action: '<Action ID>', connectionId: '<Connection ID>' } },
|
|
324
336
|
'poll': { config: { key: '<Trigger key>', schedule: [{ type: 'every', unit: 'minute', value: 5 }] } },
|
|
325
337
|
'integration': { config: { key: '<Trigger key>' } },
|
|
338
|
+
'dedupe': { config: { field: 'id', mode: 'new', space: 'node' }, inputs: { items: { kind: 'value', value: [{ id: 'a' }, { id: 'b' }] } } },
|
|
326
339
|
'http-request': { config: {}, inputs: { url: { kind: 'value', value: 'https://example.com' } } },
|
|
327
340
|
'openapi': { config: { sourceUrl: 'https://example.com/openapi.json', path: '/items', method: 'get' } },
|
|
328
341
|
'code': { code: 'export default ({value}) => ({result:value})', inputs: { value: { kind: 'value', value: 'Hello' } } },
|
|
@@ -17,7 +17,7 @@ export type AuthoringCapability = Exclude<TaskCapability, WorkflowCapability> |
|
|
|
17
17
|
export type WorkflowLookup = (flowId: string) => Promise<WorkflowContract | WorkflowCandidate>
|
|
18
18
|
|
|
19
19
|
interface ToolIdentity {
|
|
20
|
-
readonly kind?:
|
|
20
|
+
readonly kind?: string
|
|
21
21
|
readonly name?: string
|
|
22
22
|
readonly flowId?: string
|
|
23
23
|
}
|
|
@@ -4,8 +4,8 @@ import type { ConnectorConnection, CreateEventSource, ResultInfo, PollTriggerTes
|
|
|
4
4
|
import type { ProviderAccessIdentity } from './providerAccess.ts'
|
|
5
5
|
|
|
6
6
|
import { dequal } from 'dequal/lite'
|
|
7
|
-
import { currentEngineContract as engineContract } from '../../execution/common/engineContract.ts'
|
|
8
7
|
import { upgradeRevisionContent } from '../../flow/common/change.ts'
|
|
8
|
+
import { currentEngineContract as engineContract } from '../../runtime/common/engineContract.ts'
|
|
9
9
|
import { ControlClient, decodeRunEvent } from './api.ts'
|
|
10
10
|
import { allConnectorConnectionsQuery } from './connectorQueries.ts'
|
|
11
11
|
|
|
@@ -14,10 +14,10 @@ import type {
|
|
|
14
14
|
ProviderAccessBindingCandidate,
|
|
15
15
|
} from './api.ts'
|
|
16
16
|
|
|
17
|
+
import { providerIconAppearance } from '../../connector/common/providerIconSprite.ts'
|
|
17
18
|
import { exact, requiredFields, integer, invalidResponse, jsonValue, record, string } from './decoding.ts'
|
|
18
19
|
import { ApiError } from './errors.ts'
|
|
19
20
|
import { parseProviderAccessSource } from './providerAccess.ts'
|
|
20
|
-
import { providerIconAppearance } from './providerIconSprite.ts'
|
|
21
21
|
|
|
22
22
|
export function leinaBots(value: unknown): readonly LeinaBot[] {
|
|
23
23
|
const source = record(value)
|
|
@@ -42,6 +42,9 @@ export const controlErrorCode = {
|
|
|
42
42
|
triggerKeyInvalid: 'trigger-key.invalid',
|
|
43
43
|
triggerKeyNotFound: 'trigger-key.not-found',
|
|
44
44
|
triggerNotFound: 'trigger.not-found',
|
|
45
|
+
tagInvalid: 'tag.invalid',
|
|
46
|
+
tagConflict: 'tag.conflict',
|
|
47
|
+
tagNotFound: 'tag.not-found',
|
|
45
48
|
variableInvalid: 'variable.invalid',
|
|
46
49
|
variableLimitReached: 'variable.limit-reached',
|
|
47
50
|
variableNotFound: 'variable.not-found',
|
|
@@ -93,6 +96,9 @@ export const controlErrorMetadata = {
|
|
|
93
96
|
[controlErrorCode.triggerKeyInvalid]: { status: 409 },
|
|
94
97
|
[controlErrorCode.triggerKeyNotFound]: { status: 404 },
|
|
95
98
|
[controlErrorCode.triggerNotFound]: { status: 404 },
|
|
99
|
+
[controlErrorCode.tagInvalid]: { status: 400 },
|
|
100
|
+
[controlErrorCode.tagConflict]: { status: 409 },
|
|
101
|
+
[controlErrorCode.tagNotFound]: { status: 404 },
|
|
96
102
|
[controlErrorCode.variableInvalid]: { status: 400 },
|
|
97
103
|
[controlErrorCode.variableLimitReached]: { status: 409 },
|
|
98
104
|
[controlErrorCode.variableNotFound]: { status: 404 },
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import { eventSourceViewSchema } from '../../event-source/common/view.ts'
|
|
2
3
|
|
|
3
4
|
const id = z.string().min(1).max(256)
|
|
4
5
|
const eventType = z.string().regex(/^[a-z][a-z0-9_.:]{0,127}$/)
|
|
@@ -10,45 +11,17 @@ const eventSourceSchema = z.object({
|
|
|
10
11
|
revision: z.int().positive(),
|
|
11
12
|
name,
|
|
12
13
|
provider: z.enum(['feishu', 'feishu_app_bot', 'slackbot', 'intercom', 'sentry', 'zoom', 'fireflies', 'jira']),
|
|
13
|
-
|
|
14
|
-
workspaceId: id.optional(),
|
|
15
|
-
installationId: id.optional(),
|
|
16
|
-
organizationId: id.optional(),
|
|
17
|
-
projectId: id.optional(),
|
|
18
|
-
projectKey: id.optional(),
|
|
19
|
-
subscriptionStatus: z.enum(['idle', 'pending', 'ready', 'error']).optional(),
|
|
20
|
-
lastError: z.string().optional(),
|
|
21
|
-
signingSecretConfigured: z.boolean().optional(),
|
|
14
|
+
...eventSourceViewSchema.shape,
|
|
22
15
|
connectionId: id,
|
|
23
16
|
teamId: id.nullable(),
|
|
24
17
|
enabled: z.boolean(),
|
|
25
18
|
eventTypes: z.array(eventType),
|
|
26
|
-
manageSubscriptions: z.boolean().nullable(),
|
|
27
|
-
verificationTokenConfigured: z.boolean().nullable(),
|
|
28
|
-
encryptKeyConfigured: z.boolean().nullable(),
|
|
29
19
|
endpointUrl: z.string().nullable(),
|
|
30
|
-
verifiedAt: z.string().nullable(),
|
|
31
20
|
lastReceivedAt: z.string().nullable(),
|
|
32
21
|
updatedAt: z.string(),
|
|
33
22
|
consumers: z.array(z.object({ flowId: id, flowName: z.string(), triggerNodeId: id })),
|
|
34
23
|
})
|
|
35
24
|
|
|
36
|
-
export const eventSourceViewSchema = eventSourceSchema.pick({
|
|
37
|
-
appId: true,
|
|
38
|
-
workspaceId: true,
|
|
39
|
-
installationId: true,
|
|
40
|
-
organizationId: true,
|
|
41
|
-
projectId: true,
|
|
42
|
-
projectKey: true,
|
|
43
|
-
subscriptionStatus: true,
|
|
44
|
-
lastError: true,
|
|
45
|
-
signingSecretConfigured: true,
|
|
46
|
-
manageSubscriptions: true,
|
|
47
|
-
verificationTokenConfigured: true,
|
|
48
|
-
encryptKeyConfigured: true,
|
|
49
|
-
verifiedAt: true,
|
|
50
|
-
})
|
|
51
|
-
|
|
52
25
|
export interface CreateFeishuEventSource {
|
|
53
26
|
readonly kind?: 'feishu'
|
|
54
27
|
readonly version: 1
|
|
@@ -60,6 +60,7 @@ export function flow(value: unknown): Flow {
|
|
|
60
60
|
revisionId: string(target.revisionId),
|
|
61
61
|
},
|
|
62
62
|
}),
|
|
63
|
+
tagIds: source.tagIds === undefined ? [] : strings(source.tagIds),
|
|
63
64
|
createdAt: string(source.createdAt),
|
|
64
65
|
...(source.connectorTeamId == null ? {} : { connectorTeamId: string(source.connectorTeamId) }),
|
|
65
66
|
draftRevisionId: string(source.draftRevisionId),
|
|
@@ -5,6 +5,7 @@ import { canvasCommandSchema } from '../../canvas/common/commands.ts'
|
|
|
5
5
|
import { runStatuses } from '../../execution/common/runLifecycle.ts'
|
|
6
6
|
import { waitCommentSchema } from '../../execution/common/wait.ts'
|
|
7
7
|
import { resourceNameIssue } from '../../flow/common/change.ts'
|
|
8
|
+
import { stateQuerySchema, stateClearSchema, dedupeClearSchema } from '../../state/common/state.ts'
|
|
8
9
|
import { authoringReadSchema, authoringSearchSchema, authoringRequestSchema, authoringSchemaQuery } from './authoringSchema.ts'
|
|
9
10
|
import { resultQuerySchema } from './resultQuery.ts'
|
|
10
11
|
|
|
@@ -50,6 +51,21 @@ function tool<Args>(description: string, schema: z.ZodType<Args>, readOnly: bool
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
export const mcpTools = {
|
|
54
|
+
flow_state: tool(
|
|
55
|
+
'Inspect Flow state usage, business keys and deduplication spaces. Values are omitted unless requested. Scope is required.',
|
|
56
|
+
stateQuerySchema.extend({ flowId: flow }),
|
|
57
|
+
true,
|
|
58
|
+
),
|
|
59
|
+
flow_state_clear: tool(
|
|
60
|
+
'Delete one business state key or clear all business values. Explicit draft/live scope is required; live changes production state immediately.',
|
|
61
|
+
stateClearSchema.extend({ flowId: flow }),
|
|
62
|
+
false,
|
|
63
|
+
),
|
|
64
|
+
flow_dedupe_clear: tool(
|
|
65
|
+
'Clear one deduplication space (flow or node:<id>). Explicit draft/live scope is required; live changes production history immediately.',
|
|
66
|
+
dedupeClearSchema.extend({ flowId: flow }),
|
|
67
|
+
false,
|
|
68
|
+
),
|
|
53
69
|
flow_canvas: tool(
|
|
54
70
|
'Broadcast a transient canvas command to connected Workbenches viewing this Flow. Success only confirms Server broadcast, not delivery or execution. No replay, session selection or Presentation save. Pan uses screen pixels (positive right/down); zoom is an absolute ratio (0.1–3); fit includes all nodes. Repeating pan moves again.',
|
|
55
71
|
z.strictObject({ flowId: flow, command: canvasCommandSchema }),
|
|
@@ -18,6 +18,8 @@ const json: z.ZodType<JsonValue> = z.json()
|
|
|
18
18
|
const id = z.string().min(1)
|
|
19
19
|
const version = z.literal(1)
|
|
20
20
|
const flowName = id.refine((value) => value == value.trim() && resourceNameIssue(value) == null, 'Flow name is invalid.')
|
|
21
|
+
const tagIds = z.array(id).transform((ids) => [...new Set(ids)].toSorted())
|
|
22
|
+
const tagName = id.transform((name) => name.trim()).refine((name) => resourceNameIssue(name) == null, 'Tag name is invalid.')
|
|
21
23
|
const inputs = z.record(z.string(), z.record(z.string(), json))
|
|
22
24
|
const trigger = z.strictObject({ nodeId: id, outputs: z.record(z.string(), json) })
|
|
23
25
|
const schemas = {
|
|
@@ -31,8 +33,11 @@ const schemas = {
|
|
|
31
33
|
createEventSource: createEventSourceSchema,
|
|
32
34
|
updateEventSource: updateEventSourceSchema,
|
|
33
35
|
eventSourceRevision: eventSourceRevisionSchema,
|
|
34
|
-
importFlow: z.strictObject({ file: json, name: flowName.optional(), teamId: id.optional(), version }),
|
|
35
|
-
createFlow: z.strictObject({ name: flowName, teamId: id.optional(), version }),
|
|
36
|
+
importFlow: z.strictObject({ file: json, name: flowName.optional(), teamId: id.optional(), tagIds: tagIds.optional(), version }),
|
|
37
|
+
createFlow: z.strictObject({ name: flowName, teamId: id.optional(), tagIds: tagIds.optional(), version }),
|
|
38
|
+
saveTag: z.strictObject({ name: tagName, version }),
|
|
39
|
+
setFlowTags: z.strictObject({ tagIds, version }),
|
|
40
|
+
updateFlow: z.union([z.strictObject({ name: flowName, tagIds: tagIds.optional(), version }), z.strictObject({ name: flowName.optional(), tagIds, version })]),
|
|
36
41
|
renameFlow: z.strictObject({ name: flowName, version }),
|
|
37
42
|
changeDraft: z.strictObject({ expectedRevisionId: id, operations: z.array(json).min(1), version }),
|
|
38
43
|
repairDraft: z.strictObject({ expectedRevisionId: id, version }),
|
|
@@ -79,6 +84,9 @@ export const controlRequests = {
|
|
|
79
84
|
eventSourceRevision: decoder(schemas.eventSourceRevision),
|
|
80
85
|
importFlow: decoder(schemas.importFlow),
|
|
81
86
|
createFlow: decoder(schemas.createFlow),
|
|
87
|
+
saveTag: decoder(schemas.saveTag),
|
|
88
|
+
setFlowTags: decoder(schemas.setFlowTags),
|
|
89
|
+
updateFlow: decoder(schemas.updateFlow),
|
|
82
90
|
renameFlow: decoder(schemas.renameFlow),
|
|
83
91
|
changeDraft(value: unknown): { expectedRevisionId: string; operations: readonly DraftOperation[]; version: 1 } {
|
|
84
92
|
const body = schemas.changeDraft.parse(value)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FlowQuery, Tag, TagListItem } from './api.ts'
|
|
2
|
+
|
|
3
|
+
import { integer, invalidResponse, record, string } from './decoding.ts'
|
|
4
|
+
|
|
5
|
+
export function normalizeFlowQuery(query: FlowQuery = {}): Required<FlowQuery> {
|
|
6
|
+
return { query: query.query?.trim().toLowerCase() ?? '', tagIds: [...new Set(query.tagIds ?? [])].toSorted(), untagged: query.untagged ?? false }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function decodeTag(value: unknown): Tag {
|
|
10
|
+
const source = record(value)
|
|
11
|
+
if (source.version != 1) return invalidResponse()
|
|
12
|
+
return { tagId: string(source.tagId), name: string(source.name), version: 1 }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function decodeTagListItem(value: unknown): TagListItem {
|
|
16
|
+
const source = record(value)
|
|
17
|
+
const referenceCount = integer(source.referenceCount)
|
|
18
|
+
if (referenceCount < 0) return invalidResponse()
|
|
19
|
+
return { ...decodeTag(source), referenceCount }
|
|
20
|
+
}
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import type { TriggerKeySnapshot } from '../../flow/common/change.ts'
|
|
2
2
|
import type { UiLanguage } from '../../localization/common/languages.ts'
|
|
3
|
+
import type { TriggerDisplay } from '../../trigger/providers/localization.ts'
|
|
3
4
|
import type { TriggerKeySummary } from './api.ts'
|
|
4
5
|
|
|
5
6
|
import { isUiLanguage } from '../../localization/common/languages.ts'
|
|
6
7
|
import { exact, requiredFields, invalidResponse, record, string } from './decoding.ts'
|
|
7
8
|
import { triggerKey } from './triggerDecoders.ts'
|
|
8
9
|
|
|
9
|
-
export interface TriggerDisplay {
|
|
10
|
-
readonly configInputs: Readonly<Record<string, string>>
|
|
11
|
-
readonly configInputLabels: Readonly<Record<string, string>>
|
|
12
|
-
readonly displayName: string
|
|
13
|
-
readonly description: string
|
|
14
|
-
readonly outputs: Readonly<Record<string, string>>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
10
|
export interface TriggerCatalog {
|
|
18
11
|
readonly version: 3
|
|
19
12
|
readonly locale: UiLanguage
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InputPort, JsonValue,
|
|
1
|
+
import type { InputPort, JsonValue, ManagedTaskDefinitionOf, Port, TaskExecutor } from '../../flow/common/model.ts'
|
|
2
2
|
|
|
3
3
|
import { dequal } from 'dequal/lite'
|
|
4
4
|
import { matchesSchema } from '../../flow/common/schema.ts'
|
|
@@ -18,6 +18,10 @@ export interface DecisionIssue {
|
|
|
18
18
|
readonly message: string
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function isDecisionExecutor(executor: TaskExecutor): executor is DecisionExecutor {
|
|
22
|
+
return executor.kind === 'decision'
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
export const decisionModel = 'typesafe/jev'
|
|
22
26
|
export const decisionLimits = { choice: 255, score: 10 } as const
|
|
23
27
|
|
|
@@ -34,8 +38,8 @@ export function limitDecisionQuestions(questions: readonly DecisionQuestion[]):
|
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/** Loading an oversized task also updates its previously generated output schemas. */
|
|
37
|
-
export function limitDecisionTask(task:
|
|
38
|
-
if (task.executor
|
|
41
|
+
export function limitDecisionTask<Task extends ManagedTaskDefinitionOf<TaskExecutor>>(task: Task): Task {
|
|
42
|
+
if (!isDecisionExecutor(task.executor)) return task
|
|
39
43
|
const original = task.executor.questions
|
|
40
44
|
const questions = limitDecisionQuestions(original)
|
|
41
45
|
if (questions === original) return task
|
|
@@ -45,7 +49,8 @@ export function limitDecisionTask(task: ManagedTaskDefinition): ManagedTaskDefin
|
|
|
45
49
|
if (index < 0 || original[index] === questions[index] || !dequal(port.jsonSchema, answerSchema(original[index]!))) return port
|
|
46
50
|
return { ...port, jsonSchema: decisionAnswerSchema(questions[index]!) }
|
|
47
51
|
})
|
|
48
|
-
|
|
52
|
+
// Only the decision executor and its derived outputs change, so the task keeps its own type.
|
|
53
|
+
return { ...task, executor: { ...task.executor, questions }, outputs } as Task
|
|
49
54
|
}
|
|
50
55
|
export const decisionStateSchema: JsonValue = { type: ['string', 'object', 'array'] }
|
|
51
56
|
const probability: JsonValue = { type: 'number', minimum: 0, maximum: 1 }
|
|
@@ -102,7 +107,10 @@ function answerSchema(question: DecisionQuestion): JsonValue {
|
|
|
102
107
|
return { type: 'object', properties, required: Object.keys(properties) }
|
|
103
108
|
}
|
|
104
109
|
|
|
105
|
-
export function decisionTask(
|
|
110
|
+
export function decisionTask(
|
|
111
|
+
questions: readonly DecisionQuestion[] = [defaultDecisionQuestion()],
|
|
112
|
+
name = 'AI Decision',
|
|
113
|
+
): ManagedTaskDefinitionOf<DecisionExecutor> {
|
|
106
114
|
questions = limitDecisionQuestions(questions)
|
|
107
115
|
const inputs: InputPort[] = [
|
|
108
116
|
{ handle: 'target', description: 'Text, object, or array to evaluate across all questions.', jsonSchema: decisionStateSchema, nullable: false },
|
|
@@ -111,9 +119,9 @@ export function decisionTask(questions: readonly DecisionQuestion[] = [defaultDe
|
|
|
111
119
|
return { name, executor: { kind: 'decision', questions }, inputs, outputs }
|
|
112
120
|
}
|
|
113
121
|
|
|
114
|
-
export function decisionTaskIssues(task:
|
|
122
|
+
export function decisionTaskIssues(task: ManagedTaskDefinitionOf<TaskExecutor>): readonly DecisionIssue[] {
|
|
115
123
|
task = limitDecisionTask(task)
|
|
116
|
-
if (task.executor
|
|
124
|
+
if (!isDecisionExecutor(task.executor)) return []
|
|
117
125
|
const expected = decisionTask(task.executor.questions, task.name)
|
|
118
126
|
return [
|
|
119
127
|
...decisionQuestionIssues(task.executor.questions),
|