WEBVTT

NOTE Sentence-level transcript of https://www.youtube.com/watch?v=YqJ4asgj1R8

NOTE One cue per sentence. Cue ids are the line anchors on /transcripts/YqJ4asgj1R8.html. A cue ends where the next begins, or 2 s after its last word.

s1
00:00:01.309 --> 00:00:03.309
[music]

s2
00:00:12.760 --> 00:00:14.120
My name is Kim Maida.

s3
00:00:14.120 --> 00:00:24.440
I work at Keycard and Keycard provides agent access identity and access at runtime for agents.

s4
00:00:24.520 --> 00:00:25.720
Oh my.

s5
00:00:25.720 --> 00:00:26.240
Hi everyone.

s6
00:00:26.240 --> 00:00:27.320
My name is Mason Egger.

s7
00:00:27.320 --> 00:00:35.280
I'm a solutions architect at Temporal and Temporal provides durable execution to your software applications up into and including agents.

s8
00:00:35.280 --> 00:00:38.280
So, not just agents, but pretty much the entire the entire stack.

s9
00:00:38.280 --> 00:00:40.280
So.

s10
00:00:43.400 --> 00:00:47.840
So, everything you're going to need for the workshop is at the link that's on the screen right now.

s11
00:00:47.840 --> 00:01:02.400
You actually do not need to sign up for Keycard ahead of time because the sign up will be included like within the curriculum, but in order to get an account for your own personal use, if you want to play with Keycard on your own after the workshop,

s12
00:01:02.400 --> 00:01:10.720
you can go to the link that is provided at the bottom and enter that registration code in order to sign up for a personal account.

s13
00:01:16.080 --> 00:01:17.120
Okay.

s14
00:01:17.120 --> 00:01:25.480
So, we'll come back to this slide, but I am going to start out by talking a little bit about agent access.

s15
00:01:26.240 --> 00:01:34.080
So, one of the things that we do a lot of these days is give API keys to agents to give them access to resources, right?

s16
00:01:34.080 --> 00:01:36.680
And there's several problems with doing things this way.

s17
00:01:36.680 --> 00:01:42.880
One being credentials aren't attributed to a user identity or an agent identity.

s18
00:01:42.880 --> 00:01:48.800
The agent has unrestricted access to any and all permissions in that API key.

s19
00:01:48.800 --> 00:01:57.560
And finally, we can't just sort of stick human in the loop everywhere because humans make mistakes, too, and many agents also run autonomously.

s20
00:01:59.120 --> 00:02:04.412
So, the way we solve this Keycard is by using an open standard called token exchange.

s21
00:02:04.412 --> 00:02:14.572
This This standard has actually been around since 2020 and it extends OAuth 2 and I am going to show you what we're going to be doing today.

s22
00:02:16.852 --> 00:02:24.212
So, in order to give identity to an agent and the user behind the agent, we need to know who the user is as first order of business.

s23
00:02:24.212 --> 00:02:28.012
So, an authorization server verifies identities and issues tokens.

s24
00:02:28.012 --> 00:02:33.332
Identity providers like Google, Okta, Auth0, etc. provide authorization servers.

s25
00:02:33.332 --> 00:02:40.772
And if we want to get an identity chain in the agent execution path, then we need the user to log in first.

s26
00:02:42.212 --> 00:02:53.372
After logging in, the authorization server prompts user for their consent to delegate some portion of their access to resources with a subset of their permissions called scopes.

s27
00:02:53.372 --> 00:02:55.732
Now, this is kind of the first narrowing of access, right?

s28
00:02:55.732 --> 00:03:00.772
We're only delegating some of the user's total access to the agent.

s29
00:03:01.812 --> 00:03:09.292
And the authorization server issues a token I that identifies the user and includes their level of access.

s30
00:03:10.692 --> 00:03:22.492
So, now if we go into what actually happens in the agent execution path, we have an authenticated user now with a known identity who wants to use an LLM to interact with resources.

s31
00:03:22.652 --> 00:03:29.692
Now, an agent is a control loop that calls an LLM and in this workshop, that agent is an expense desk agent.

s32
00:03:29.692 --> 00:03:32.572
That's what we're going to be working with.

s33
00:03:32.932 --> 00:03:38.932
It's going to call in an expense MCP server which sits between the agent and a ledger API.

s34
00:03:38.932 --> 00:03:46.292
This provides the agent with a defined set of tools and it also provides the connection to that downstream resource.

s35
00:03:47.732 --> 00:03:54.972
Now, an MCP client takes the agent's proposed tool calls and it dispatches them to its MCP server.

s36
00:03:55.932 --> 00:03:59.772
The runtime is a process that runs with the agent loop and executes calls.

s37
00:03:59.772 --> 00:04:05.494
So, in our case today, the Expense Desk application is the runtime.

s38
00:04:06.734 --> 00:04:12.614
We're going to use a LangChain agent that's implemented in this custom Expense Desk app.

s39
00:04:13.094 --> 00:04:21.654
So, if we follow a prompt through this execution path, the user submits the prompt to the runtime, which calls the model and sends it to the LLM.

s40
00:04:21.654 --> 00:04:31.614
The model proposes tool calls, which are then dispatched by the MCP client to its MCP server, which executes the tools, and then calls the resource API.

s41
00:04:32.974 --> 00:04:36.414
The API returns a response to the MCP server.

s42
00:04:36.414 --> 00:04:46.014
The MCP client delivers the response to the runtime, which calls the model, and this loop repeats until the model is satisfied and returns the response to the user.

s43
00:04:50.534 --> 00:04:55.454
Now, if you remember, we have an authenticated user with a token identifying who they are.

s44
00:04:55.454 --> 00:05:03.054
And this token becomes what we call a subject token as identifies the subject on whose behalf the agent is going to act.

s45
00:05:03.494 --> 00:05:09.054
So, in order to support token exchange, we need an OAuth client that's capable of executing code.

s46
00:05:09.054 --> 00:05:19.174
So, that might be a gateway between the MCP client and maybe a third-party MCP server, or a custom agent app, or a CLI wrapper around an off-the-shelf coding agent.

s47
00:05:19.174 --> 00:05:28.174
In this case today, the Expense Desk agent is a custom agent app that implements token exchange for access to the Expense MCP server.

s48
00:05:28.974 --> 00:05:35.054
This MCP server also supports token exchange for the next downstream resource, which is the ledger API.

s49
00:05:35.054 --> 00:05:40.214
This connects to the database where the expenses are actually going to be stored.

s50
00:05:41.214 --> 00:05:45.734
Now, the prompt and the subject token are sent to the Expense Desk agent app.

s51
00:05:45.734 --> 00:05:50.054
The agent loop runs, and the model proposes a tool call.

s52
00:05:52.054 --> 00:05:56.414
The Expense Desk agent authenticates with Keycloak's security token service.

s53
00:05:56.414 --> 00:05:59.574
Now, this is a special authorization server.

s54
00:05:59.574 --> 00:06:07.575
And the Expense Desk agent can authenticate using its client credentials or a workload identity.

s55
00:06:07.575 --> 00:06:14.415
It also sends the user's subject token that declares the user's identity and their level of authorization.

s56
00:06:14.975 --> 00:06:25.215
Now the expense desk OAuth client creates a token exchange request asking permission to access the MCP server for that tool call, but only that one specific tool call.

s57
00:06:25.215 --> 00:06:28.655
So now we basically have three pieces of information.

s58
00:06:29.735 --> 00:06:33.495
We have the identity of the agent that's requesting access.

s59
00:06:33.495 --> 00:06:37.495
We have the identity of the user on whose behalf the agent is acting.

s60
00:06:37.495 --> 00:06:42.255
And we have the level of access that the user granted to the agent.

s61
00:06:43.615 --> 00:06:47.215
So now we need to decide if the requested token should be issued or not.

s62
00:06:47.215 --> 00:06:58.855
And we can do this with policy, which is evaluated against what access is requested from what resource, who the agent is, and who the agent is acting for.

s63
00:07:00.375 --> 00:07:10.815
Now if the delegation chain and the requested access all fall within the policy, then Keycard issues an access token that can be only only be used at the MCP server.

s64
00:07:11.535 --> 00:07:17.695
Now this issued token usually expires within minutes and you should never store it.

s65
00:07:18.135 --> 00:07:26.935
The token is sent to the expense desk MCP client, which makes a tool call to the expense MCP server using that token as a bearer credential.

s66
00:07:26.935 --> 00:07:33.255
The MCP server validates that token and then uses it to authorize a tool call.

s67
00:07:33.735 --> 00:07:37.775
The tools need access to the ledger API resource.

s68
00:07:37.775 --> 00:07:41.735
So at that point the MCP server then initiates a second hop.

s69
00:07:41.735 --> 00:07:46.095
This is where it sends its own token exchange request to Keycard.

s70
00:07:46.095 --> 00:07:59.615
And the request to exchange that token is received from the expense desk for a token to access the ledger API, which is the downstream resource.

s71
00:07:59.815 --> 00:08:10.937
Now Keycard evaluates request against policy and then mints the credential for the resource scoped only for the access that's needed for that specific tool call.

s72
00:08:11.537 --> 00:08:17.817
The MCP server receives this token and then it uses it to call the ledger API.

s73
00:08:18.657 --> 00:08:23.097
The API validates the token and then grants the appropriate requested access.

s74
00:08:23.097 --> 00:08:29.137
Now, the MCP server never stores the token and it discards it as soon as the call is done.

s75
00:08:29.657 --> 00:08:37.217
The API response then flows back up and the agentic loop repeats until the model returns the answer to the user.

s76
00:08:39.537 --> 00:08:45.777
So, at a high level, this is what you're going to see us implement today with Keycard.

s77
00:08:46.017 --> 00:08:49.457
And I'm going to pull up this slide again.

s78
00:08:49.457 --> 00:08:55.537
So, again, I'm going to basically demo or Mason and I are going to demo everything step-by-step on screen.

s79
00:08:55.537 --> 00:09:01.937
Uh you are free to follow along or if you would prefer to just watch, you can also do that.

s80
00:09:01.937 --> 00:09:07.377
Uh the workshop is going to use a pre-provisioned shared Keycard organization.

s81
00:09:07.377 --> 00:09:13.617
So, if you do participate, you are going to be in the same organization as everybody else in the room.

s82
00:09:13.617 --> 00:09:17.377
So, you'll be able to see what everybody else is doing.

s83
00:09:17.377 --> 00:09:23.097
Okay, so if you go to the link that is that was provided, you're going to see this.

s84
00:09:23.097 --> 00:09:30.257
This is the uh workshop running in essentially a sandbox.

s85
00:09:31.457 --> 00:09:32.777
So, we're going to go ahead and start this.

s86
00:09:32.777 --> 00:09:40.257
This is going to take a few min a minute or two to to uh get everything all set up.

s87
00:09:40.297 --> 00:09:47.857
But, basically, kind of the premise here is we're going to start with an expense desk agent that does not require a login.

s88
00:09:47.857 --> 00:09:56.577
It doesn't know who is acting at any point and everybody who uses the agent is using an API key.

s89
00:09:56.737 --> 00:10:04.457
So, I have some folks uh here who are going to be helping to populate the demo, essentially.

s90
00:10:04.457 --> 00:10:14.138
Um if you want to follow along as well, you would are going to eventually need uh admin access in key cards.

s91
00:10:14.138 --> 00:10:26.018
So, as we go through the workshop, when we hit that part, uh they'll be watching to see people show up uh in the user list, and they will be granting you admin access as that happens.

s92
00:10:28.658 --> 00:10:30.698
So, when you begin the workshop, this is what you're going to see.

s93
00:10:30.698 --> 00:10:35.858
So, basically, this is the application where we don't know anybody's identity.

s94
00:10:35.858 --> 00:10:40.538
Everybody is using the same MCP server, but they're all running their own agents.

s95
00:10:40.538 --> 00:10:44.058
They are all using an API key.

s96
00:10:44.058 --> 00:10:46.098
They might be using the same one, they might be using different ones.

s97
00:10:46.098 --> 00:10:49.618
We, you know, don't really have a way of knowing that.

s98
00:10:49.618 --> 00:10:56.538
But, if we look at the expense desk, it's we kind of see your your classical uh expense.

s99
00:10:56.538 --> 00:11:06.938
You file an expense, and then it either gets approved or rejected, um and then paid out, which is not actually going to happen, so you're not going to receive money.

s100
00:11:06.938 --> 00:11:14.098
Um But, basically, everything in this expense desk operates through the agent.

s101
00:11:14.098 --> 00:11:20.138
So, the first thing we are going to do is we're going to submit an expense.

s102
00:11:23.778 --> 00:11:29.498
So, I'm going to tell the agent I want to submit a $75 expense for snacks for the workshop.

s103
00:11:29.498 --> 00:11:34.298
It submits that expense, and then its status is pending.

s104
00:11:38.858 --> 00:11:48.738
Now, if we go down to the activity here, we can see that uh this expense was created using access granted by an API key.

s105
00:11:48.738 --> 00:11:48.938
Right?

s106
00:11:48.938 --> 00:11:57.258
So, we don't have any user identity, we don't know the agent's identity, the agent doesn't really have an identity yet on its own.

s107
00:11:59.578 --> 00:12:04.138
And what I'm going to do is I'm going to refresh this.

s108
00:12:04.138 --> 00:12:09.698
And I'm going to approve or deny somebody else's expense.

s109
00:12:10.898 --> 00:12:13.578
So, let's see this one.

s110
00:12:13.578 --> 00:12:20.579
If I hit approve, it's basically uh just going to send that as a prompt to the agent.

s111
00:12:21.659 --> 00:12:29.379
It went ahead and approved that expense, and now we have the created by was created by this API key.

s112
00:12:29.379 --> 00:12:32.379
So, I don't know who created that expense, right?

s113
00:12:32.379 --> 00:12:34.459
Everybody's just using API keys.

s114
00:12:34.459 --> 00:12:42.939
I approved it, but we also don't have any record of who approved it, either, because again, all we have is an API key.

s115
00:12:51.659 --> 00:12:59.699
So, the next thing that we want to do is actually give the agent an identity, so that it can act on its own behalf.

s116
00:13:05.699 --> 00:13:13.419
Uh so, the first thing we are going to do now is we are going to join that shared Keycard organization.

s117
00:13:13.659 --> 00:13:26.539
So, if you click the link, if you're following along, if you click the link in the instructions, you will be able to you will get a prompt to log in with GitHub, and you can sign up with GitHub

s118
00:13:26.539 --> 00:13:28.179
to join Keycard.

s119
00:13:28.179 --> 00:13:44.779
When you get in, you should say see this workshop AI NYC in the upper left corner, indicating that you're in the right uh organization, and let me move this around so we can see things better.

s120
00:13:53.139 --> 00:13:53.979
Okay.

s121
00:13:53.979 --> 00:13:59.499
So, if you're following along, when you join, you're likely to see a couple of consent prompts.

s122
00:13:59.499 --> 00:14:11.579
These are what I kind of talked about earlier in the presentation, where you are delegating some subset of your access to the agent to use on your behalf.

s123
00:14:17.139 --> 00:14:19.461
So, this is the key card console.

s124
00:14:19.461 --> 00:14:22.021
The first thing I want to talk about is applications.

s125
00:14:22.021 --> 00:14:26.141
Now, applications and resources are registrations.

s126
00:14:26.141 --> 00:14:29.341
So, something can be both an application and a resource.

s127
00:14:29.341 --> 00:14:38.021
And basically, what this means is applications are things that are going to be able to make requests for tokens.

s128
00:14:38.021 --> 00:14:46.741
They're going to ask for token exchanges in order to then exchange on down the line to access other resources.

s129
00:14:46.741 --> 00:14:55.221
So, our The first thing we want to do is we want to create an application registration for our agent.

s130
00:14:55.221 --> 00:15:06.021
So, what we are going to do here is I'm going to call this agent app.

s131
00:15:09.141 --> 00:15:18.461
And then in order because we're all in the same uh organization here, we want to name things so that we can find our own applications and resources that we created.

s132
00:15:18.461 --> 00:15:22.101
So, I'm going to use the my GitHub handle.

s133
00:15:24.221 --> 00:15:26.381
Every app's identifier needs to be unique.

s134
00:15:26.381 --> 00:15:31.021
So, we are going to do something similar here.

s135
00:15:32.661 --> 00:15:36.261
We're going to use implicit consent.

s136
00:15:36.261 --> 00:15:39.821
And then we need to grab our redirect URL.

s137
00:15:39.821 --> 00:15:45.581
Now, this is something that we can get out of our uh sandbox image.

s138
00:15:45.581 --> 00:15:50.661
So, if we go into this.

s139
00:15:50.661 --> 00:15:54.141
I don't know why that one won't come to the front.

s140
00:15:58.581 --> 00:16:00.861
Go to the terminal.

s141
00:16:00.941 --> 00:16:04.461
We are going to run this.

s142
00:16:04.461 --> 00:16:10.021
This gives you the redirect URL that is specific to your instance of the sandbox.

s143
00:16:10.021 --> 00:16:13.541
So, I'm just going to copy that.

s144
00:16:15.941 --> 00:16:22.702
I'm going to Oops, don't need to add this as a redirect URL.

s145
00:16:24.702 --> 00:16:32.982
So, after there's a login event, this is where the user is going to be redirected back to.

s146
00:16:32.982 --> 00:16:35.862
And I'm going to say create application.

s147
00:16:42.982 --> 00:16:50.102
So, now we have a registration that says our expense desk agent can request tokens, right?

s148
00:16:50.102 --> 00:16:59.102
So, but our expense desk agent can also receive tokens because it's going to receive the subject token from the user when the user logs in.

s149
00:16:59.102 --> 00:17:10.422
And in order to do that, we basically need to do another registration, and we need to say that this agent application can also act as a resource, which means it is a target recipient

s150
00:17:10.422 --> 00:17:12.222
for tokens.

s151
00:17:12.222 --> 00:17:18.542
So, the authentication token is the token that this agent is going to be receiving.

s152
00:17:18.542 --> 00:17:22.622
So, if we go into resources, we can add another resource.

s153
00:17:22.622 --> 00:17:30.342
We are going to call this one The first one was agent app, this one is agent resource.

s154
00:17:30.622 --> 00:17:34.022
I'm going to use my GitHub name.

s155
00:17:34.622 --> 00:17:37.142
Let's use a similar identifier.

s156
00:17:37.142 --> 00:17:39.822
This is the agent resource.

s157
00:17:44.742 --> 00:17:58.022
I'm going to set the credential provider to zone provider, which essentially means that Keycloak is the entity that's going to be handling the token exchange and issuing uh tokens for this resource.

s158
00:18:05.102 --> 00:18:15.422
And then I'm going to come down here, and I'm going to say this resource is being provided by my application, the agent app came out of.

s159
00:18:15.982 --> 00:18:24.023
So, basically, this is the relationship that tells Keycloak that uh this application can exchange sign-in tokens addressed to this resource.

s160
00:18:24.023 --> 00:18:29.703
If we don't make this association, then the exchange requests are going to be rejected.

s161
00:18:33.703 --> 00:18:36.903
So, I'm going to save that.

s162
00:18:38.463 --> 00:18:44.863
And now I want to add the things that my agent application depends on.

s163
00:18:44.863 --> 00:18:51.223
So, if I come back to applications, I find my application.

s164
00:18:52.463 --> 00:18:58.183
I'm going to go into dependencies, and then I'm going to look at the list of dependencies, and I'm going to add something here.

s165
00:18:58.183 --> 00:19:11.503
So, the first one I'm going to add is the agent resource, and we need this because our agent application is going to request token exchanges to access uh downstream resources.

s166
00:19:11.503 --> 00:19:18.263
We also want to be able to request token exchanges for the expense MCP server.

s167
00:19:18.263 --> 00:19:20.663
So, this is a resource that's already been preconfigured for you.

s168
00:19:20.663 --> 00:19:26.783
Everybody is using the same one, so we don't need to create a bunch of them that are all named after ourselves.

s169
00:19:29.143 --> 00:19:38.863
Additionally, we have an agent, and we want to have the API key for that agent stored in Keycard so that we don't have its secret on disk.

s170
00:19:38.863 --> 00:19:46.263
So, Keycard also provides a vault, and we have that API key configured in the vault already for you.

s171
00:19:46.263 --> 00:19:51.223
So, we can select the LLM API.

s172
00:19:51.223 --> 00:19:59.703
And finally, we're going to select this user info endpoint as well, because this is going to be able to tell us who the logged-in user is.

s173
00:19:59.703 --> 00:20:03.943
It's going to be able to provide us with that identity information.

s174
00:20:04.383 --> 00:20:06.703
So, I'm going to say connect.

s175
00:20:11.743 --> 00:20:24.385
Now, the next thing I need to do is I need to give this agent app an its own identity, and I can't really do that unless it has some way to identify itself to essentially log in.

s176
00:20:24.385 --> 00:20:26.785
Uh so, I'm going to click on add credential.

s177
00:20:26.785 --> 00:20:31.065
I'm going to click on client ID and secret.

s178
00:20:34.425 --> 00:20:41.505
Now, wait.

s179
00:20:42.705 --> 00:20:44.905
We're going to go into the editor.

s180
00:20:44.905 --> 00:20:48.505
We are going into the agent folder.

s181
00:20:48.505 --> 00:20:51.145
We're going to find the end file.

s182
00:20:51.145 --> 00:20:59.425
And we are going to paste in that client ID and that client secret.

s183
00:21:01.625 --> 00:21:03.985
This is the secret.

s184
00:21:04.825 --> 00:21:09.585
Now, we're doing this because this is essentially like a sandbox local environment.

s185
00:21:09.585 --> 00:21:15.345
If you were using this in a production environment, you would probably use work something like workload identity.

s186
00:21:15.345 --> 00:21:24.865
Also, Keycard provides a CLI which can populate secrets for you dynamically and not require them to be on disk.

s187
00:21:25.505 --> 00:21:30.385
And then finally, I'm going to tell it what the identifier for the agent resource is.

s188
00:21:30.385 --> 00:21:37.305
So, that was my your an agent resource and then my GitHub name.

s189
00:21:37.305 --> 00:21:40.785
Going to wait until this says changes saved.

s190
00:21:47.145 --> 00:21:53.265
And at this point, we have configured Keycard to be able to handle the token exchanges and exchange requests.

s191
00:21:53.265 --> 00:22:01.145
Now, what we need to do is make sure that our expense desk application can actually handle that.

s192
00:22:01.585 --> 00:22:12.585
So, essentially, when we go and look at the code here, we find that in the agent folder, we have this agent off.

s193
00:22:12.585 --> 00:22:17.425
If we go down, we find Okay, this thing is in the way.

s194
00:22:19.305 --> 00:22:21.945
I'm trying to move that.

s195
00:22:28.425 --> 00:22:41.066
This we're going to find the checkpoint, which So, this this is the file where we don't have any authenticated MCP access, right?

s196
00:22:41.426 --> 00:22:49.426
Now, the way the workshop works is if you at each lesson we have a checkpoint that will provide the code essentially for the end of that lesson.

s197
00:22:49.426 --> 00:22:55.866
So, what we can do now is we can go and look for the checkpoint for exercise two, which is the one that we're at.

s198
00:22:55.866 --> 00:23:03.506
So, if we go to checkpoints, we go to authenticated, and then we find the same file.

s199
00:23:14.026 --> 00:23:16.546
Where are we here?

s200
00:23:25.026 --> 00:23:25.546
Okay.

s201
00:23:25.546 --> 00:23:27.826
So, we want to find this MCP tool set.

s202
00:23:27.826 --> 00:23:34.906
This is passing in the keycard zone token off from the keycard SDK.

s203
00:23:34.906 --> 00:23:44.586
And this is what is going to actually make that token request every time the agent actually wants to make a tool call with the MCP server.

s204
00:23:44.586 --> 00:23:51.906
So, for every individual tool call, we're going to get a token that's scoped to that specific tool call.

s205
00:24:01.026 --> 00:24:20.586
Now, this call is the this is Okay.

s206
00:24:20.586 --> 00:24:31.668
So, now if we go to the keycard file, we look for this mint function.

s207
00:24:31.668 --> 00:24:41.148
This is what actually goes ahead and makes that request to mint a token for the exchange.

s208
00:24:41.148 --> 00:24:52.947
So, if we don't have a subject token, that is if we don't have a logged in user, then the agent is actually going to authenticate as itself using a client credentials grant.

s209
00:24:52.947 --> 00:24:59.788
So, it's going to use that uh client ID and client secret to identify itself to Keycloak.

s210
00:24:59.788 --> 00:25:03.788
And this means it's acting on its own behalf.

s211
00:25:08.268 --> 00:25:18.107
Okay, so now if we go to the terminal tab, we basically want to make sure that we activate this updated code.

s212
00:25:18.668 --> 00:25:23.827
So, we're going to uh run that so it switches over to checkpoint two.

s213
00:25:24.227 --> 00:25:27.187
And then we have to restart the services.

s214
00:25:30.587 --> 00:25:31.148
Stop.

s215
00:25:31.148 --> 00:25:33.427
There it goes.

s216
00:25:34.507 --> 00:25:49.627
Okay, now if we go and look at the expense desk, we have the screen that will let us continue with an authenticated expense desk agent.

s217
00:25:49.627 --> 00:25:58.827
So, if we go ahead and click continue as the agent, then we're going to ask it uh which I can just copy this.

s218
00:25:58.827 --> 00:26:02.307
Which account is being used right now?

s219
00:26:02.307 --> 00:26:06.148
And what is my approval limit?

s220
00:26:06.148 --> 00:26:14.067
And the approval limit is essentially the amount of money that you as a user are allowed to approve for other people's expenses.

s221
00:26:15.148 --> 00:26:30.148
So, it says I'm signed in as the expense desk agent K Mida, which was in Keycloak that was the uh specific application that we are acting as that we provided the client ID and secret for.

s222
00:26:30.388 --> 00:26:35.389
And the approval limit for the agent is about $50.

s223
00:26:37.029 --> 00:26:58.869
So next I am going to tell the agent file a $75 expense or let's just say for some swag for the workshop on my behalf.

s224
00:27:03.709 --> 00:27:07.429
So the agent submitted that expense.

s225
00:27:08.309 --> 00:27:21.549
The memo says it was it filed on behalf of Kim but the actual activity details indicate that this was filed by this specific agent.

s226
00:27:22.589 --> 00:27:25.749
So the on behalf of Kim is just something I told it.

s227
00:27:25.749 --> 00:27:37.069
It doesn't necessarily actually have any to verify that because I as a user have not signed in it created this expense under its own identity.

s228
00:27:50.229 --> 00:27:50.869
Okay.

s229
00:27:50.869 --> 00:27:57.309
So now if we go into our applications actually I probably could have left that up.

s230
00:27:57.309 --> 00:27:59.749
Oh, it's right there.

s231
00:28:00.949 --> 00:28:02.949
We can see the activity in Keycloak.

s232
00:28:02.949 --> 00:28:10.229
This is essentially the audit log that Keycloak generates of all the activities that have been happening against this application.

s233
00:28:11.749 --> 00:28:25.029
And I am going to look for specifically because there's uh several different resources here.

s234
00:28:31.869 --> 00:28:36.310
To look for the expense MCP resource.

s235
00:28:36.310 --> 00:28:43.510
Anything that was calling the expense MCP resource, I'm going to limit this to the last hour.

s236
00:28:51.910 --> 00:29:04.230
And we can see that there was a credential issued using the client credentials grant, which means that the actor was the application itself, and it was accessing the MCP resource.

s237
00:29:08.510 --> 00:29:17.270
So now I'm going to go and look for what we have already registered for you, which is the expense MCP actor.

s238
00:29:17.270 --> 00:29:37.390
So the expense MCP server has multiple registrations as well because it can receive tokens uh from the agent application, and then it can exchange that token on for a downstream token to access the ledger API.

s239
00:29:38.870 --> 00:29:51.150
So if we click on this one, now we have uh because everybody is using the same resource for the MCP server, we're going to go ahead and just filter it down

s240
00:30:00.710 --> 00:30:07.510
to it calling the ledger API.

s241
00:30:09.510 --> 00:30:22.430
And I could technically use any of these, but oops, this is looking for people.

s242
00:30:28.710 --> 00:30:43.072
So if we look at one of the calls that the expense MCP server used executed in order to exchange the token that it received from the agent application to access the ledger API.

s243
00:30:43.072 --> 00:30:56.552
We can see that the delegation chain shows that the application that made the request was the expense MCP server and that it was acting on behalf of this application.

s244
00:30:56.552 --> 00:31:01.272
And the resource that is accessing is the ledger API.

s245
00:31:01.312 --> 00:31:07.872
So, this is essentially the the record of the delegation chain for the agent acting as itself.

s246
00:31:10.912 --> 00:31:13.912
I'm going to go ahead and check that.

s247
00:31:22.632 --> 00:31:23.552
Okay.

s248
00:31:23.552 --> 00:31:35.351
So, now we have an agent that can identify itself and act as itself, but we maybe want it to act on our behalf but without impersonating us.

s249
00:31:35.351 --> 00:31:38.152
So, we don't want it to just say Kim did this.

s250
00:31:38.152 --> 00:31:44.592
We want it to say this agent did this thing on behalf of Kim with Kim's permissions.

s251
00:31:44.592 --> 00:31:51.712
So, the next thing we're going to do is we're going to add human user identity into this process.

s252
00:31:52.352 --> 00:31:54.392
So, now we have user delegation.

s253
00:31:54.392 --> 00:32:07.432
At this point, we need to load the expense desk in a new tab because the iframe that's embedded into the sandbox doesn't handle external authentication.

s254
00:32:07.432 --> 00:32:14.432
Um so, we're going to go ahead and open that in external window.

s255
00:32:15.672 --> 00:32:18.471
Put this down here.

s256
00:32:23.672 --> 00:32:26.192
And now we have this sign in button up on the right.

s257
00:32:26.192 --> 00:32:29.592
I'm going to click that.

s258
00:32:29.592 --> 00:32:35.512
If it's spinning.

s259
00:32:36.392 --> 00:32:37.032
Okay.

s260
00:32:37.032 --> 00:32:42.033
So, because I was already logged in, it went ahead and logged me in automatically.

s261
00:32:42.033 --> 00:32:49.353
Um but now what I can do is I can say we can see that my email is here.

s262
00:32:49.633 --> 00:33:03.913
If I ask the agent which account am I using now, before it said you're use you're acting as this agent, now it knows that I have an identity because I authenticated as a human user.

s263
00:33:03.913 --> 00:33:04.193
All right.

s264
00:33:04.193 --> 00:33:11.113
And my approval limit, which is associated with my identity metadata, is $100.

s265
00:33:19.553 --> 00:33:23.673
So, I haven't filed any expenses under my human user yet.

s266
00:33:23.673 --> 00:33:35.913
So, if I change this filter to to show all expenses, you can see that these expenses from earlier still um say that they were submitted by the API key.

s267
00:33:35.913 --> 00:33:40.633
Like, adding all of this doesn't go back and change anything that's happened in the past.

s268
00:33:40.633 --> 00:33:48.793
And we can see, you know, examples of the Expense Desk agent acting on behalf of other people as well.

s269
00:33:51.513 --> 00:34:01.393
So, we have the ability now to act as ourself as a human user, but we have still retained the ability for the agent to act as itself as well.

s270
00:34:01.393 --> 00:34:12.993
And the way that kind of plays out in this workshop is by the agent having the capability approve expenses that are under a certain amount of money.

s271
00:34:16.673 --> 00:34:22.193
So, if I I'm just going to do this one.

s272
00:34:23.113 --> 00:34:36.833
If I submit an expense for, say, $30 for office supplies for the team, it's going to verify who I am, it's going to file the expense.

s273
00:34:47.394 --> 00:35:00.874
And then because the agent actually has the ability to approve expenses under $49.99 on its own, it filed the expense and then the agent approved it as itself.

s274
00:35:01.234 --> 00:35:10.074
So if I click on the activity to examine what happened here, it says that this expense was created by me under my email.

s275
00:35:11.834 --> 00:35:15.714
And then it was approved by the expense desk agent.

s276
00:35:17.354 --> 00:35:28.714
So it shows, you know, that this is the identifier for the agent that acted in the approval and it gives a reason says eligible office supplies under $50 with a clear business purpose.

s277
00:35:30.314 --> 00:35:42.354
Uh so now maybe I want to Let's do this $75 one as well.

s278
00:35:47.914 --> 00:35:56.314
So if I submit an expense that is over that approval limit that the agent can act on on its own, then the status for that one is pending.

s279
00:35:56.314 --> 00:35:59.434
A human needs to review it.

s280
00:35:59.634 --> 00:36:04.234
If I go and say, "Hey uh I think this should be approved.

s281
00:36:04.234 --> 00:36:11.474
So I'm going to send the message to the agent that says, 'Hey, approve expense 123.'"

s282
00:36:16.874 --> 00:36:19.994
It says, "I can't approve or reject my own expense.

s283
00:36:19.994 --> 00:36:22.114
So I have to ask another reviewer to do that."

s284
00:36:22.114 --> 00:36:25.114
And it's able to do that because we have identities now.

s285
00:36:25.114 --> 00:36:32.154
We know who all of the users are, who are logged in, and we also know the identity of the agent itself.

s286
00:36:33.394 --> 00:36:37.550
Uh so before we didn't demonstrate this, but before I could have approved

s287
00:36:37.550 --> 00:36:37.914
[music]

s288
00:36:37.914 --> 00:36:42.874
my own expenses or anybody else's because it didn't know who anybody was.

s289
00:36:43.874 --> 00:36:47.716
So if I go here, let's see.

s290
00:36:53.636 --> 00:37:00.476
Let's find somebody else's pending expense.

s291
00:37:01.876 --> 00:37:09.236
I'm going to say, uh, I want to reject this one.

s292
00:37:24.436 --> 00:37:26.156
The agent goes through that song and dance.

s293
00:37:26.156 --> 00:37:37.956
And now if we look at the recorded activity for this expense, it says that it was created by the expense desk agent, uh, because it was from kind of the previous cycle.

s294
00:37:38.356 --> 00:37:43.956
And it was rejected by my identity.

s295
00:37:44.716 --> 00:37:52.356
So, now we have a kind of a clear record of who filed what, who approved or rejected what.

s296
00:37:56.356 --> 00:38:07.836
So, if we go into the KeyCloak console at this point, go to applications, we are going to find the Kitematic application.

s297
00:38:09.596 --> 00:38:11.196
I'm going to clear any previous filters.

s298
00:38:11.196 --> 00:38:14.356
I think they're already gone.

s299
00:38:14.356 --> 00:38:19.316
I'm going to say actor, and I'm going to look for my email.

s300
00:38:21.276 --> 00:38:25.676
Change this to hour.

s301
00:38:26.476 --> 00:38:42.996
And if I click on one of these issued credentials, I can see that the application that, uh, made the token exchange request was my application agent app Kitematic, and it was acting on behalf of me, the human user

s302
00:38:42.996 --> 00:38:50.477
Kitematic KeyCloak or Kitematic KeyCloak, and it was accessing the expense MCP resource.

s303
00:38:50.877 --> 00:38:52.517
So, that was the first hop, right?

s304
00:38:52.517 --> 00:39:04.117
So, now if we go over to the applications again and we want to find the expense MCP actor.

s305
00:39:12.557 --> 00:39:14.637
Actually, I don't think we need to filter anything.

s306
00:39:14.637 --> 00:39:16.637
It's all here.

s307
00:39:16.637 --> 00:39:20.477
And we go to a credential that was issued for access to the ledger API.

s308
00:39:20.477 --> 00:39:32.357
We can now see that on the second hop, the expense MCP server made the request on behalf of me and it was accessing the ledger API.

s309
00:39:33.637 --> 00:39:48.197
So, on the first hop, what happened is the agent took my sign-in token that it acquired when I logged in as my human user and it exchanged the it made a token exchange request to keycard

s310
00:39:48.197 --> 00:39:55.597
offering that sign-in token in exchange for a token for the next thing in in the uh chain, right?

s311
00:39:55.597 --> 00:39:57.597
Which is the MCP server.

s312
00:39:57.597 --> 00:40:01.237
So, it exchanged the subject token for an MCP server token.

s313
00:40:01.237 --> 00:40:09.237
It then took that MCP server token and called the MCP server to make tool call with the appropriate tool scoped scopes.

s314
00:40:09.237 --> 00:40:21.677
And then the MCP server took that token that it had received from the agent and it made a token exchange request to keycard asking to give that token up for

s315
00:40:21.677 --> 00:40:28.357
a token to access the ledger API, which was the next resource in the stream.

s316
00:40:30.517 --> 00:40:34.517
And you can trace these hops.

s317
00:40:35.837 --> 00:40:40.317
You can trace these things across hops because they have a session associated with them.

s318
00:40:40.317 --> 00:40:50.997
So, we're not going to spend a whole lot of time like digging into the the session numbers and copying them, but you can follow any specific sequence of events

s319
00:40:50.997 --> 00:40:58.398
uh by the session number will be consistent on the first hop and also the second hop.

s320
00:41:08.198 --> 00:41:10.518
I can close all of that.

s321
00:41:10.518 --> 00:41:14.878
And I will now give it up to Mason.

s322
00:41:14.878 --> 00:41:15.318
Awesome.

s323
00:41:15.318 --> 00:41:16.758
Thank you so much, Kim.

s324
00:41:16.758 --> 00:41:19.318
I have my little plushy tardigrade Ziggy goes with me everywhere.

s325
00:41:19.318 --> 00:41:20.558
We have plenty of them.

s326
00:41:20.558 --> 00:41:22.158
So, make sure you grab one before you leave.

s327
00:41:22.158 --> 00:41:24.438
Take one home for your kids or for yourself.

s328
00:41:24.438 --> 00:41:25.798
No shame.

s329
00:41:25.798 --> 00:41:26.558
Whatever you'd like to do.

s330
00:41:26.558 --> 00:41:31.518
So, we won't just walk through how to build all of this security and stuff into our agent and stuff.

s331
00:41:31.518 --> 00:41:41.238
But now, how do we deploy these agents to ensure that they execute to their completion, that they don't fail or when they do fail, we know how to handle that, and we know how to

s332
00:41:41.238 --> 00:41:45.238
reliably bring them back up so we don't lose all of our process and waste a whole bunch of time and compute.

s333
00:41:45.238 --> 00:41:48.678
And that's where Temporal comes into play.

s334
00:41:48.678 --> 00:41:49.278
[clears throat]

s335
00:41:49.278 --> 00:41:52.598
So, Temporal is a durable execution framework.

s336
00:41:52.598 --> 00:41:57.878
So, essentially what it does is we take your code, we execute it, we maintain the state of the application.

s337
00:41:57.878 --> 00:42:05.598
If the application were to fail, run into an error, things of that nature, it will reconstruct the state or rebuild the state to the point of failure and continue executing

s338
00:42:05.598 --> 00:42:06.398
onwards.

s339
00:42:06.398 --> 00:42:14.878
Certain things such as function calls and things if say a distributed system were to go down, there are built-in retries and all sorts of failure handling modes.

s340
00:42:14.878 --> 00:42:22.038
So, one of the things that we've seen a lot of with the customers that I work with and with our users is that we need a way of making

s341
00:42:22.038 --> 00:42:23.558
your agents durable.

s342
00:42:23.558 --> 00:42:27.838
And in reality, the agent loop is or the agent itself is just a loop.

s343
00:42:27.838 --> 00:42:31.918
It's a it's a loop of ever calling tool calls to external services.

s344
00:42:31.918 --> 00:42:36.918
Agents are just distributed systems at the end of the day with a little bit of added spice on top with some thinking.

s345
00:42:36.918 --> 00:42:43.078
But the problems that we've solved for distributed systems apply to agent loops, and this is where Temporal comes in.

s346
00:42:43.078 --> 00:42:51.518
It works out really well to keep your application running and going so you don't lose data, so you don't have to re- call LLMs, uh tokens and all of that nature.

s347
00:42:51.518 --> 00:42:54.240
So, you So, your users don't experience any sort of outage.

s348
00:42:54.240 --> 00:42:56.280
All sorts of really awesome things with that.

s349
00:42:56.280 --> 00:43:01.840
So, what we're going to do a little bit is just kind of talk about a little bit of how you would structure uh Temporal application code.

s350
00:43:01.840 --> 00:43:03.360
I'll leave this here for you to read later.

s351
00:43:03.360 --> 00:43:11.880
I'm not going to dive super deep into the code itself, but essentially Temporal is a a system where you can you build a workflow and you define it by things what are called activities.

s352
00:43:11.880 --> 00:43:14.560
Think parent function and child function calls.

s353
00:43:14.560 --> 00:43:15.840
Easiest way to think about it.

s354
00:43:15.840 --> 00:43:20.200
We implement our loop uh as a this parent function call and this becomes a workflow.

s355
00:43:20.200 --> 00:43:28.280
And every single uh instance of or execution of this uh workflow, so like every single time we would have keycard go through and uh authenticate for user, that would be a workflow.

s356
00:43:28.280 --> 00:43:31.040
And every single tool call is essentially an activity.

s357
00:43:31.040 --> 00:43:37.760
These are things that can fail, that we expect to fail, and when they do fail, we either retry them or we rebuild the state and see what happens with it.

s358
00:43:37.760 --> 00:43:39.640
So, we have our workflow calls here.

s359
00:43:39.640 --> 00:43:42.960
I'm also I do the other direction for Mac Mac mouse.

s360
00:43:42.960 --> 00:43:46.680
So, if I go the wrong direction, it's cuz I'm not not using my laptop.

s361
00:43:46.680 --> 00:43:49.440
Um I remap everything on my computer.

s362
00:43:49.440 --> 00:43:51.760
Uh and then down here you actually see like this async def SS.

s363
00:43:51.760 --> 00:43:53.840
This is actually uh what an activity would look like.

s364
00:43:53.840 --> 00:43:55.400
So, you it looks like normal Python code.

s365
00:43:55.400 --> 00:43:57.240
It looks like the typical code you would write.

s366
00:43:57.240 --> 00:44:02.840
Temporal is a code-first system, so you can build all of your things and hook it into anything that you would want.

s367
00:44:02.840 --> 00:44:06.720
Um so we have our settlement code workflow, which I'm not going to read through too much.

s368
00:44:06.720 --> 00:44:07.760
I'll leave that to you for you.

s369
00:44:07.760 --> 00:44:15.480
But again, it's a Temporal workflow that uh essentially allows us to set how often we want to retry, and then we execute the activities.

s370
00:44:15.480 --> 00:44:20.400
We have our um our debit ledger right here and our mark settled.

s371
00:44:20.400 --> 00:44:23.120
So, we're able to, you know, add something to the ledger and then mark it as settled.

s372
00:44:23.120 --> 00:44:30.480
And we have this timer here in the middle for us to kind of simulate some like uh human-in-the-loop time that it would wait take for someone to do this.

s373
00:44:30.480 --> 00:44:37.400
Uh and then one of our activities uh for this, as you can see here, is uh this section right here, which is just the typical code.

s374
00:44:37.400 --> 00:44:42.720
But I want to draw your line your eye to the to the first decorator on top, which is grant uh resource.

s375
00:44:42.720 --> 00:44:48.960
So, Temporal exposes a lot of native uh primitives within its code base, uh one of which is what's called an interceptor.

s376
00:44:48.960 --> 00:44:53.520
So, it allows you at certain points within the code to allow for essentially think of them as hooks.

s377
00:44:53.520 --> 00:45:05.681
So, this is actually something that the Keycard team uh implemented, which is where whenever this um this activity is being executed, it actually goes and gets permission and gets an identity from Keycard,

s378
00:45:05.681 --> 00:45:16.681
and then comes back, and essentially now we are able to authenticate this through uh our Temporal workflow and our activities through this, and we can maintain this identity separation that Kim was talking about, where you can have each individual worker have its own one.

s379
00:45:16.681 --> 00:45:23.521
You can have a fleet of them have their own, but you'd be able to identify and limit scope, access, all of those wonderful things uh through there.

s380
00:45:23.521 --> 00:45:31.761
Um so, the next thing we're going to do is we're basically going to find uh our work I think we already did the workers' identity in Keycard.

s381
00:45:31.761 --> 00:45:32.161
Yeah.

s382
00:45:32.161 --> 00:45:33.361
Okay, so we're going to start our worker.

s383
00:45:33.361 --> 00:45:38.001
So, we actually already set up our Temporal application and set up all of these uh environment variable configurations.

s384
00:45:38.001 --> 00:45:40.201
So, let's go ahead and start uh our worker.

s385
00:45:40.201 --> 00:45:43.881
So, Temporal is a worker-server model a version of execution.

s386
00:45:43.881 --> 00:45:48.401
You There's a Temporal service that maintains the execution, the application state, all of that.

s387
00:45:48.401 --> 00:45:49.801
And then there's a fleet of workers.

s388
00:45:49.801 --> 00:45:56.721
You can think Kubernetes pods, processes within a pod that your work as it's being uh as it gets as the request comes in.

s389
00:45:56.721 --> 00:46:04.761
So, from here we'll go to start worker, and we'll just start our first worker right here, and so, we have worker PID 572 running.

s390
00:46:04.761 --> 00:46:12.281
So, now we have a uh automatic uh a Temporal worker that's running the agent that was just done in the previous thing in the previous exercise, which will automatically

s391
00:46:12.281 --> 00:46:14.841
uh accept our uh expenses.

s392
00:46:14.841 --> 00:46:18.921
So, we have our worker running right here, and we see our PID is 572.

s393
00:46:18.921 --> 00:46:20.081
And then we can start a settlement.

s394
00:46:20.081 --> 00:46:28.201
So, what we're going to do is we're going to click on this client tab here, and we're going to invoke a settlement uh that's going to happen, and we'll see our workflow ID settlement came up.

s395
00:46:28.201 --> 00:46:36.281
So, if we go back to our worker tab here, we'll actually see the output of our Temporal application as it's logging out what it is doing, and it's currently

s396
00:46:36.281 --> 00:46:42.361
doing it as you can see here, we debited a token um and minted it for this particular call, and then we're running it.

s397
00:46:42.361 --> 00:46:48.161
If we go to our Temporal Web UI, and we refresh this here, we can actually see our application running.

s398
00:46:48.161 --> 00:46:51.761
I have to do this a little quickly, and then I can continue talking.

s399
00:46:51.761 --> 00:46:53.841
Oh, no, it's not control Is it There it is.

s400
00:46:53.841 --> 00:46:56.601
Okay, command-control-C you Macs is not fun for me.

s401
00:46:56.601 --> 00:46:58.843
So, we had our application running.

s402
00:46:58.843 --> 00:47:00.283
We said we had our debit ledger.

s403
00:47:00.283 --> 00:47:02.003
I killed the application cold.

s404
00:47:02.003 --> 00:47:05.122
So, as you can see here, the running state of this application is gone.

s405
00:47:05.122 --> 00:47:06.362
We no longer have it.

s406
00:47:06.362 --> 00:47:09.162
In a traditional system, this would be potentially problematic.

s407
00:47:09.162 --> 00:47:16.642
We would have to you know, either have saved that state to a database and then re- uh rehydrate it when it comes back online.

s408
00:47:16.642 --> 00:47:22.602
But, uh with Temporal, that's not really a problem because to the state of our application is stored right here inside of it.

s409
00:47:22.602 --> 00:47:27.203
So, the very first uh the debit ledger uh function stored the output right here.

s410
00:47:27.203 --> 00:47:29.563
So, we have a retry policy uh activity task completed.

s411
00:47:29.563 --> 00:47:31.323
We debited 4,200.

s412
00:47:31.323 --> 00:47:32.243
So, we have that done.

s413
00:47:32.243 --> 00:47:36.563
There's nothing running right now, so it's going to start complaining and telling me, "Hey, you have nothing running.

s414
00:47:36.563 --> 00:47:38.402
Our workflow task has timed out."

s415
00:47:38.402 --> 00:47:40.203
We have a dead application.

s416
00:47:40.203 --> 00:47:42.362
Uh and then we go back to our worker mid-settlement.

s417
00:47:42.362 --> 00:47:46.362
Whenever we're ready, we can just restart the worker.

s418
00:47:47.563 --> 00:47:51.003
And the application picks up as if the if the failure never happened.

s419
00:47:51.003 --> 00:47:55.243
It rebuilt the entire state of our agent from all of the previous responses.

s420
00:47:55.243 --> 00:47:56.843
No LLM calls were redone.

s421
00:47:56.843 --> 00:47:59.563
No previous activities or functions were re-executed.

s422
00:47:59.563 --> 00:48:07.083
It has picked up the state, replayed the actions, and then pushed it through, and we got the execution to work.

s423
00:48:07.483 --> 00:48:09.642
So, why does durability matter for agents?

s424
00:48:09.642 --> 00:48:11.203
Well, uh your agents are loops.

s425
00:48:11.203 --> 00:48:15.083
Um there's a lot of things inside of your agents right now that cost a lot of money.

s426
00:48:15.083 --> 00:48:18.723
Making LLM calls on on a massive scale is not cheap.

s427
00:48:18.723 --> 00:48:20.003
There's their tokens you have to deal with.

s428
00:48:20.003 --> 00:48:21.442
There's a lot of failure states.

s429
00:48:21.442 --> 00:48:22.602
There's a lot of advanced states.

s430
00:48:22.602 --> 00:48:27.483
Say you get through a really long loop and you know, you're 12 steps in and you lose the entire state of that application.

s431
00:48:27.483 --> 00:48:36.682
Now you either have you've either had to built basically built a version of Temporal yourself where you are maintaining the state of your application in a database somewhere, and then you have to build all the reconstruction

s432
00:48:36.682 --> 00:48:43.003
logic and all the retry logic, or uh you can use something like a durable execution system like Temporal, and it will do all of this for you.

s433
00:48:43.003 --> 00:48:51.362
So, this allows for you to have your agents go offline, fail, your LLM provider can go down, you can lose an entire region in AWS.

s434
00:48:51.362 --> 00:48:59.043
Doesn't matter when they when those when that compute comes back when those resources come back online, the agents pick up right where they left off at the exact last spot and continue execution.

s435
00:48:59.043 --> 00:49:05.604
And if it happens quickly enough, if it's a quick enough failure, your user will never even be aware that they that they lost service of this.

s436
00:49:05.604 --> 00:49:15.604
Um if you had been on the receiving end of this worker call that I had just done where we waited a minute and you were knew you were going to wait a minute for the approval and that failure happened and it happened and I restarted the worker within,

s437
00:49:15.604 --> 00:49:17.284
you know, 5 seconds of the failure.

s438
00:49:17.284 --> 00:49:22.604
As a user on the client side, you probably never would even notice that there was this kind of failure and that's what Temporal does.

s439
00:49:22.604 --> 00:49:28.284
Is it brings it all the way out uh for you and just keeps the execution going forward regardless.

s440
00:49:28.284 --> 00:49:35.244
Now, the interesting thing is um the secrets for all of this were actually not inside of our Temporal event history.

s441
00:49:35.244 --> 00:49:40.764
So, if we go back to our client over here and we run this command, oop, I hit a button.

s442
00:49:40.764 --> 00:49:42.484
Oh, I have to actually put in the correct workflow ID.

s443
00:49:42.484 --> 00:49:44.204
If I don't, it doesn't work.

s444
00:49:44.204 --> 00:49:48.324
If I go back here and collect this workflow ID.

s445
00:49:49.324 --> 00:49:51.404
Uh it's on the client tab.

s446
00:49:51.404 --> 00:49:52.324
Yeah.

s447
00:49:52.324 --> 00:49:55.084
And we click the up arrow.

s448
00:49:56.364 --> 00:49:59.644
Now, we're going to hope I know how to paste on Mac.

s449
00:49:59.644 --> 00:50:00.604
Aha, we got it.

s450
00:50:00.604 --> 00:50:01.884
Good.

s451
00:50:01.884 --> 00:50:07.524
So, we can actually see we actually have a little little Python script here that says that no JWT token uh material uh was basically sent.

s452
00:50:07.524 --> 00:50:14.324
We didn't like our worker through the entire event history here, um you can see the the starting process and the result.

s453
00:50:14.324 --> 00:50:20.444
So, if we click in, I can see the debit ledger here with the result down here.

s454
00:50:20.444 --> 00:50:23.964
So, we have our uh each individual function is stored there.

s455
00:50:23.964 --> 00:50:27.644
So, our second function here, mark settled, was also uh settled as well.

s456
00:50:27.644 --> 00:50:35.324
So, this was the result of it, but nowhere in our workflow if I go to the actual event history, which is this is actually what the event history looks like under the hood,

s457
00:50:35.324 --> 00:50:38.724
you will not find it anywhere uh because we didn't store it.

s458
00:50:38.724 --> 00:50:43.644
Um so, Temporal gives you basically two different ways uh to keep the sensitive data out.

s459
00:50:43.644 --> 00:50:45.884
So, we have the interceptor, which is what Keycard provided for us.

s460
00:50:45.884 --> 00:50:53.404
So, they built an interceptor that basically injects it at uh uh keeps the data and the credentials out of it entirely and then injects it back in when it's time to execute.

s461
00:50:53.404 --> 00:50:56.964
Think of it like almost like just-in-time credentials uh and does that.

s462
00:50:56.964 --> 00:51:01.244
Or the other thing for Temporal that's really awesome is there's what's called a payload uh encoder.

s463
00:51:01.244 --> 00:51:08.325
So, what you can do is you saw in our Temporal Web UI, your data was There we go.

s464
00:51:08.325 --> 00:51:09.365
Wrong button.

s465
00:51:09.365 --> 00:51:12.965
Your data is just sitting here in nice wonderful plain text.

s466
00:51:12.965 --> 00:51:15.045
You have the ability to encrypt this yourself.

s467
00:51:15.045 --> 00:51:19.125
So, you can basically spin up There's like a There's an entire pattern and library in Temporal.

s468
00:51:19.125 --> 00:51:29.045
You spin up a sidecar, you create an encryption algorithm, you set what the encryption policy is, and all data that comes to Temporal, whether it's self-hosted or in the cloud, is

s469
00:51:29.045 --> 00:51:30.005
essentially encrypted.

s470
00:51:30.005 --> 00:51:31.525
And we can't read it.

s471
00:51:31.525 --> 00:51:32.325
We don't control your keys.

s472
00:51:32.325 --> 00:51:34.725
We honestly don't quite care about what you're doing inside of it.

s473
00:51:34.725 --> 00:51:35.725
That's not the part that we care about.

s474
00:51:35.725 --> 00:51:38.725
We care about putting all these fancy things in order.

s475
00:51:38.725 --> 00:51:43.885
So, that's a quick overview of like Temporal and building out it building out agents with it.

s476
00:51:43.885 --> 00:51:45.965
There's a lot of integrations with Temporal you can try out.

s477
00:51:45.965 --> 00:51:49.405
There's an Open AI, Pydantic AI.

s478
00:51:49.405 --> 00:51:52.925
I know there's LangChain and a whole bunch of other ones too as well.

s479
00:51:52.925 --> 00:51:57.525
Um And I think we even now have like an agentic harness now that we've been building out that's going out too.

s480
00:51:57.525 --> 00:52:01.405
So, you can come by and see us at our booth if you want to learn more about that.

s481
00:52:01.405 --> 00:52:09.645
Um And yeah, so the expense desk, you know, basically we I'll bring him back up to kind of wrap it up and we can take some questions if you want.

s482
00:52:09.645 --> 00:52:19.765
Building out the agent identity, building out all of the agent worker and all of that stuff, and then Temporal becomes the execution layer to make sure that your agent runs properly

s483
00:52:19.765 --> 00:52:27.405
and doesn't fail in the case of, you know, any sort of cataclysmic failure, API outage, AWS region just decides it wants to disappear for a day, which does happen.

s484
00:52:27.405 --> 00:52:30.485
So, yeah, that's all I have.
