Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data Driven Intents #201

Closed
nkolba opened this issue May 26, 2020 · 6 comments
Closed

Data Driven Intents #201

nkolba opened this issue May 26, 2020 · 6 comments
Labels
enhancement New feature or request

Comments

@nkolba
Copy link
Contributor

nkolba commented May 26, 2020

Enhancement Request

Intents in FDC3 should be able to return data payloads.

Use Cases:

Some use cases for data resolving intents include:

Symbol Resolution

As an end user, I may want to initiate an FDC3 workflow from an app providing news or other unstructured data. For example, "International Business Machines" appearing in a body of text. Resolving the string to structured instrument data - as well as disambiguating the instrument the end user may want to work with - is critical to routing the end user to the right workflow.

Price Quotes

As an end user, I will have content that is not directly hooked to a pricing system. Enabling inline pricing in any app and with the pricing system of my choice would provide great value in alleviating the need for me to context switch between multiple apps.

Placing Orders

As an end user, I want to leverage the OMS of my choice, and to be able to slot in a new system - without relying on backend integrations between vendors or being forced to rekey to fill last mile gaps. An end user should be able to receive an inquiry in a chat, place an order with the OMS of choice, and send a confirmation # back to the requester without leaving the chat application.

Workflow Description

  • An intent is raised as it is today.
  • This intent is resolved against known applications providing the intent.
  • If there is ambiguity, the end user chooses which app they wish to resolve the intent.
  • The app is launched (if needed) and is passed the intent and any accompanying context
  • The resolved app returns the requested data and this is passed back to the calling app as the resolution of the intent.

Workflow Examples

For pricing:
A grid provider has enabled realtime pricing for their watch list app. They add a button to their app to "get prices". When selected, this will raise a 'getPrice' event for the instrumentList. The end user will be prompted to choose the pricing service they want to use. The prices will be returned (and the intent resolved) and the grid will update its UI.

Additional Information

Related issue #127

Some previously floated ideas around implementation:

  • Returned data would be treated as Context Data and standardized (for standard intents)
  • The intent definition for data intents would be expanded to specify the context data type returned

To consider:

  • Streaming data
@nkolba nkolba added the enhancement New feature or request label May 26, 2020
@nkolba
Copy link
Contributor Author

nkolba commented May 28, 2020

Questions:
Do we need to distinguish between background (no UI) and visual (with UI) intent resolvers?

How do we handle delayed/failed return of data?

How do we manage return data structures for different asset classes?

@kriswest
Copy link
Contributor

kriswest commented May 28, 2020

The name for this issue doesn't match the proposal well (IMHO), which describes 'IntentResolutions with data' or 'Resolving Intents with Data' (rather than intents that were driven by data, although I concede they might have been driven by a desire to retrieve data).

@rikoe
Copy link
Contributor

rikoe commented Jun 25, 2020

I think to support this use case, we will need to extend the app directory schema to specify intent return types.

Two suggested example use cases:

  • ExecuteTrade intent, which needs a success/failure indication. This could be an intent without UI, another application handles the trade execution in the background without user involvement.
  • SelectCounterparty intent, which is an interactive intent that returns data. Another application will show UX to select a counterparty based on an instrument, and the return it.
{
    "intents": [
        {
            "name": "ExecuteTrade",
            "displayName": "Execute a trade",
            "contexts": ["fdc3.tradeInstruction"],
            "result": "fdc3.tradeResult"
        },
        {
            "name": "SelectCounterparty",
            "displayName": "Select a counterparty",
            "contexts": ["fdc3.instrument"],
            "result": "fdc3.counterparty"
        }

    ]
}

Example context types:

const instrument = {
    type: 'fdc3.instrument',
    id: {
        ticker: 'AAPL'
    }
}
const tradeInstruction = {
    type: 'fdc3.tradeInstruction',
    instrument,
    notional: 1000000
}

const tradeResult = {
    type: 'fdc3.tradeResult',
    id: {
        tradeId: "1fdkjfd273-x4"
    },
    timestamp: "2012-04-23T18:25:43.511Z",
    success: true
}

const counterparty = {
    type: 'fdc3.counterparty',
    contact: {
        type: 'fdc3.contact',
        name: 'Joe Bloggs',
        id: {
            email: 'joe.bloggs@mail.com'
        }
    },
    organization: {
        type: 'fdc3.orgainization',
        name: 'Cargill, Incorporated',
        id: {
            LEI: 'QXZYQNMR4JZ5RIRN4T31',
            FDS_ID: '00161G-E'
        }
    }
}

@rikoe
Copy link
Contributor

rikoe commented Jun 25, 2020

Supporting the current IntentResolution.data property, would require extending the intent listener signature to support return values.

Current signature:

type Context = object;
type ContextHandler = (context: Context) => void;

addIntentListener(intent: string, handler: ContextHandler): Listener;

New signature:

type Context = object;
type IntentContextHandler = (context: Context) => Context | void;

interface DesktopAgent {
    addIntentListener(intent: string, handler: IntentContextHandler): Listener;
}

Example intent listener for a one-way intent (FDC3 1.1):

const listener = fdc3.addIntentListener('ViewAnalysis', (instrument: Instrument) => {
  // handle instrument
})

Example intent listener for a two-way intent:

// ExecuteTrade
const listener = fdc3.addIntentListener('ExecuteTrade', tradeInstruction => {
    return {
        type: 'fdc3.tradeResult',
        id: {
            tradeId: '1fdkjfd273-x4',
        },
        timestamp: Date.now(),
        success: true
    }
})

// SelectCounterparty
const listener = fdc3.addIntentListener('SelectCounterparty', (instrument: Instrument) => {

    // show selection UI

    return {
        type: 'fdc3.counterparty',
        contact,
        organization
    }
})

@rikoe
Copy link
Contributor

rikoe commented Jun 25, 2020

How do raising two-way intents work? Well, this is interesting. It depends how you want to resolve the promise. Is the intent being delivered the same as the data being returned? Here we assume the raising application will wait for the data to be returned.

I prefer leveraging generics in TypeScript to make the code a bit easier to deal with.

// execute a trade
const resolution = await fdc3.raiseIntent<TradeResult>("ExecuteTrade", tradeInstruction)
if (resolution.data.success) {
    // ...
} else {
    // ...
}

// select a counterparty
const resolution = await fdc3.raiseIntent<Counterparty>("SelectCounterparty", instrument)
const counterparty = resolution.data

How do the types change to enable this?

interface IntentResolution<T extends Context> {
    source: string;
    data?: T;
    version: string;
}

interface DesktopAgent {
    raiseIntent<T extends Context>(intent: string, context: Context, target?: string): Promise<IntentResolution<T>>;
}

The problem here is that such a signature is hard to make work for one-way intents that don't need a return data type, you would still need to specify one anyway.

Maybe we can use a dedicated method for intents that return data, which would also make it nice and clear when reading the code what the intention is:

interface DesktopAgent {
    raiseIntent(intent: string, context: Context, target?: string): Promise<IntentResolution>;
    raiseIntentForData<TData extends Context>(intent: string, context: Context, target?: string): Promise<IntentResolution<TData>>;
}

@nkolba
Copy link
Contributor Author

nkolba commented Nov 22, 2020

PR #287 has now been created addressing this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants