@loopstack/github-oauth-example 0.2.0 → 0.2.2

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.
Files changed (2) hide show
  1. package/README.md +116 -20
  2. package/package.json +14 -9
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > An example module for the [Loopstack AI](https://loopstack.ai) automation framework.
4
4
 
5
- This module demonstrates how to build workflows that interact with the GitHub API using OAuth authentication. It includes two workflows: a structured overview that fetches repository data, and an interactive chat agent powered by an LLM that can use all 25 GitHub tools.
5
+ This module demonstrates how to build workflows that interact with the GitHub API using OAuth authentication. It includes two workflows: a structured overview that fetches repository data, and an interactive chat agent powered by Claude that can use all 25 GitHub tools.
6
6
 
7
7
  ## Workflows
8
8
 
@@ -15,16 +15,70 @@ A multi-step workflow that fetches and displays a comprehensive overview of a Gi
15
15
  **Flow:**
16
16
 
17
17
  ```
18
- start -> fetch_user -> fetch_orgs -> fetch_repo_details -> fetch_issues_prs
19
- -> fetch_content_actions -> fetch_search -> display_results -> end
18
+ start -> user_fetched -> orgs_fetched -> repo_fetched -> issues_prs_fetched
19
+ -> content_actions_fetched -> search_done -> end
20
20
  ```
21
21
 
22
22
  With OAuth branching:
23
23
 
24
24
  ```
25
- fetch_user -> (unauthorized) -> auth_required -> awaiting_auth
26
- |
27
- auth_completed -> start (retry)
25
+ user_fetched -> (unauthorized via @Guard) -> awaiting_auth
26
+ |
27
+ auth_completed -> start (retry)
28
+ ```
29
+
30
+ **Key patterns:**
31
+
32
+ The workflow uses `@Guard` to check if authentication is needed and routes to the OAuth flow:
33
+
34
+ ```typescript
35
+ @Transition({ from: 'user_fetched', to: 'awaiting_auth', priority: 10 })
36
+ @Guard('needsAuth')
37
+ async authRequired() {
38
+ const result = await this.oAuth.run(
39
+ { provider: 'github', scopes: ['repo', 'read:org', 'workflow'] },
40
+ { alias: 'oAuth', callback: { transition: 'authCompleted' } },
41
+ );
42
+
43
+ await this.repository.save(
44
+ LinkDocument,
45
+ {
46
+ label: 'GitHub authentication required',
47
+ workflowId: result.workflowId,
48
+ embed: true,
49
+ expanded: true,
50
+ },
51
+ { id: `link_${result.workflowId}` },
52
+ );
53
+ }
54
+
55
+ needsAuth(): boolean {
56
+ return !!this.requiresAuthentication;
57
+ }
58
+ ```
59
+
60
+ The auth callback uses `wait: true` with `CallbackSchema` to receive the OAuth completion signal:
61
+
62
+ ```typescript
63
+ @Transition({
64
+ from: 'awaiting_auth',
65
+ to: 'start',
66
+ wait: true,
67
+ schema: CallbackSchema,
68
+ })
69
+ async authCompleted(payload: { workflowId: string }) {
70
+ await this.repository.save(
71
+ LinkDocument,
72
+ {
73
+ status: 'success',
74
+ label: 'GitHub authentication completed',
75
+ workflowId: payload.workflowId,
76
+ embed: true,
77
+ expanded: false,
78
+ },
79
+ { id: `link_${payload.workflowId}` },
80
+ );
81
+ }
28
82
  ```
29
83
 
30
84
  **Tools exercised in the workflow:**
@@ -61,18 +115,60 @@ All 25 tools are injected and available; 9 are called directly by the workflow t
61
115
 
62
116
  ### GitHub Agent (`gitHubAgent`)
63
117
 
64
- An interactive chat agent that gives an LLM access to all 25 GitHub tools. The agent can manage repositories, issues, pull requests, browse code, check CI/CD status, search across GitHub, and handle OAuth automatically.
118
+ An interactive chat agent that gives Claude access to all 25 GitHub tools. The agent can manage repositories, issues, pull requests, browse code, check CI/CD status, search across GitHub, and handle OAuth automatically via the `AuthenticateGitHubTask` custom tool.
65
119
 
66
120
  **How it works:**
67
121
 
68
- 1. Sets up a system prompt describing available GitHub capabilities
69
- 2. Waits for user input via a chat prompt
70
- 3. Sends the conversation to the LLM with all GitHub tools available
71
- 4. Executes any tool calls the LLM makes
72
- 5. If a tool returns an auth error, launches OAuth and resumes after authentication
122
+ 1. Sets up a hidden system message describing available GitHub capabilities
123
+ 2. Waits for user input via a `wait: true` transition
124
+ 3. Sends the conversation to Claude with all 25 GitHub tools plus `authenticateGitHub`
125
+ 4. If `stop_reason === 'tool_use'`, delegates tool calls via `DelegateToolCalls` and collects results with `UpdateToolResult`
126
+ 5. If a tool returns an auth error, the LLM calls `authenticateGitHub` which launches OAuth
73
127
  6. Loops back to wait for the next user message
74
128
 
75
- This is the easiest way to interactively test every GitHub tool — just ask the agent to perform any GitHub operation.
129
+ **Agent loop pattern:**
130
+
131
+ ```typescript
132
+ @Transition({ from: 'ready', to: 'prompt_executed' })
133
+ async llmTurn() {
134
+ const result: ToolResult<ClaudeGenerateTextResult> = await this.claudeGenerateText.call({
135
+ system: `You are a helpful GitHub assistant with access to repository, issue, PR, code, actions,
136
+ and search tools. When a tool returns an unauthorized error, use authenticateGitHub
137
+ to let the user sign in, then retry. Be concise and format results using markdown.`,
138
+ claude: { model: 'claude-sonnet-4-6' },
139
+ messagesSearchTag: 'message',
140
+ tools: [
141
+ 'gitHubListRepos', 'gitHubGetRepo', 'gitHubCreateRepo', 'gitHubListBranches',
142
+ 'gitHubListIssues', 'gitHubGetIssue', 'gitHubCreateIssue', 'gitHubCreateIssueComment',
143
+ 'gitHubListPullRequests', 'gitHubGetPullRequest', 'gitHubCreatePullRequest',
144
+ 'gitHubMergePullRequest', 'gitHubListPrReviews',
145
+ 'gitHubGetFileContent', 'gitHubCreateOrUpdateFile', 'gitHubListDirectory', 'gitHubGetCommit',
146
+ 'gitHubListWorkflowRuns', 'gitHubTriggerWorkflow', 'gitHubGetWorkflowRun',
147
+ 'gitHubSearchCode', 'gitHubSearchRepos', 'gitHubSearchIssues',
148
+ 'gitHubGetAuthenticatedUser', 'gitHubListUserOrgs',
149
+ 'authenticateGitHub',
150
+ ],
151
+ });
152
+ this.llmResult = result.data;
153
+ }
154
+
155
+ @Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 })
156
+ @Guard('hasToolCalls')
157
+ async executeToolCalls() {
158
+ const result: ToolResult<DelegateToolCallsResult> = await this.delegateToolCalls.call({
159
+ message: this.llmResult!,
160
+ document: ClaudeMessageDocument,
161
+ callback: { transition: 'toolResultReceived' },
162
+ });
163
+ this.delegateResult = result.data;
164
+ }
165
+
166
+ hasToolCalls(): boolean {
167
+ return this.llmResult?.stop_reason === 'tool_use';
168
+ }
169
+ ```
170
+
171
+ This is the easiest way to interactively test every GitHub tool -- just ask the agent to perform any GitHub operation.
76
172
 
77
173
  ## Setup
78
174
 
@@ -89,17 +185,17 @@ GITHUB_OAUTH_REDIRECT_URI=http://localhost:5173/oauth/callback
89
185
  For the GitHub Agent workflow, you also need an LLM API key:
90
186
 
91
187
  ```bash
92
- OPENAI_API_KEY=your-openai-api-key
188
+ ANTHROPIC_API_KEY=your-anthropic-api-key
93
189
  ```
94
190
 
95
191
  ## Dependencies
96
192
 
97
- - `@loopstack/core` Core framework functionality including `ExecuteWorkflowAsync`
98
- - `@loopstack/ai-module` LLM integration (`AiGenerateText`, `DelegateToolCall`)
99
- - `@loopstack/oauth-module` OAuth infrastructure (`OAuthTokenStore`, `OAuthWorkflow`)
100
- - `@loopstack/github-module` All 25 GitHub tools and the GitHub OAuth provider
101
- - `@loopstack/core-ui-module` `CreateDocument`, `LinkDocument`, `MarkdownDocument`
102
- - `@loopstack/create-chat-message-tool` `CreateChatMessage`
193
+ - `@loopstack/common` - Core framework decorators (`BaseWorkflow`, `@Workflow`, `@Initial`, `@Transition`, `@Final`, `@Guard`, `@InjectTool`, `@InjectWorkflow`, `CallbackSchema`, `ToolResult`)
194
+ - `@loopstack/core` - Provides `LinkDocument` and `MarkdownDocument`
195
+ - `@loopstack/claude-module` - Claude integration (`ClaudeGenerateText`, `ClaudeMessageDocument`, `DelegateToolCalls`, `UpdateToolResult`)
196
+ - `@loopstack/oauth-module` - OAuth infrastructure (`OAuthWorkflow`)
197
+ - `@loopstack/github-module` - All 25 GitHub tools
198
+ - `@loopstack/create-chat-message-tool` - `CreateChatMessage` (used in agent workflow)
103
199
 
104
200
  ## About
105
201
 
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "loopstack",
9
9
  "oauth"
10
10
  ],
11
- "version": "0.2.0",
11
+ "version": "0.2.2",
12
12
  "license": "Apache-2.0",
13
13
  "author": {
14
14
  "name": "Jakob Klippel",
@@ -29,13 +29,13 @@
29
29
  "watch": "nest build --watch"
30
30
  },
31
31
  "dependencies": {
32
- "@loopstack/claude-module": "^0.22.0",
33
- "@loopstack/common": "^0.25.0",
34
- "@loopstack/core": "^0.25.0",
35
- "@loopstack/create-chat-message-tool": "^0.21.0",
36
- "@loopstack/github-module": "^0.2.0",
37
- "@loopstack/oauth-module": "^0.2.0",
38
- "@nestjs/common": "^11.1.14",
32
+ "@loopstack/claude-module": "^0.22.1",
33
+ "@loopstack/common": "^0.25.1",
34
+ "@loopstack/core": "^0.25.1",
35
+ "@loopstack/create-chat-message-tool": "^0.21.2",
36
+ "@loopstack/github-module": "^0.2.2",
37
+ "@loopstack/oauth-module": "^0.2.2",
38
+ "@nestjs/common": "^11.1.19",
39
39
  "zod": "^4.3.6"
40
40
  },
41
41
  "files": [
@@ -47,7 +47,12 @@
47
47
  "rootDir": "src",
48
48
  "testRegex": ".*\\.spec\\.ts$",
49
49
  "transform": {
50
- "^.+\\.ts$": "ts-jest"
50
+ "^.+\\.ts$": [
51
+ "ts-jest",
52
+ {
53
+ "tsconfig": "tsconfig.spec.json"
54
+ }
55
+ ]
51
56
  },
52
57
  "testTimeout": 10000,
53
58
  "forceExit": true,