@loopstack/oauth-examples 0.1.1

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 (75) hide show
  1. package/README.md +111 -0
  2. package/dist/index.d.ts +8 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +24 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/oauth-examples.module.d.ts +3 -0
  7. package/dist/oauth-examples.module.d.ts.map +1 -0
  8. package/dist/oauth-examples.module.js +42 -0
  9. package/dist/oauth-examples.module.js.map +1 -0
  10. package/dist/shared/github/authenticate-github-task.tool.d.ts +26 -0
  11. package/dist/shared/github/authenticate-github-task.tool.d.ts.map +1 -0
  12. package/dist/shared/github/authenticate-github-task.tool.js +67 -0
  13. package/dist/shared/github/authenticate-github-task.tool.js.map +1 -0
  14. package/dist/shared/github/index.d.ts +2 -0
  15. package/dist/shared/github/index.d.ts.map +1 -0
  16. package/dist/shared/github/index.js +18 -0
  17. package/dist/shared/github/index.js.map +1 -0
  18. package/dist/shared/google/authenticate-google-task.tool.d.ts +26 -0
  19. package/dist/shared/google/authenticate-google-task.tool.d.ts.map +1 -0
  20. package/dist/shared/google/authenticate-google-task.tool.js +69 -0
  21. package/dist/shared/google/authenticate-google-task.tool.js.map +1 -0
  22. package/dist/shared/google/google-calendar-fetch-events.tool.d.ts +28 -0
  23. package/dist/shared/google/google-calendar-fetch-events.tool.d.ts.map +1 -0
  24. package/dist/shared/google/google-calendar-fetch-events.tool.js +96 -0
  25. package/dist/shared/google/google-calendar-fetch-events.tool.js.map +1 -0
  26. package/dist/shared/google/index.d.ts +3 -0
  27. package/dist/shared/google/index.d.ts.map +1 -0
  28. package/dist/shared/google/index.js +19 -0
  29. package/dist/shared/google/index.js.map +1 -0
  30. package/dist/workflows/github-agent/github-agent-example.ui.yaml +6 -0
  31. package/dist/workflows/github-agent/github-agent-example.workflow.d.ts +55 -0
  32. package/dist/workflows/github-agent/github-agent-example.workflow.d.ts.map +1 -0
  33. package/dist/workflows/github-agent/github-agent-example.workflow.js +243 -0
  34. package/dist/workflows/github-agent/github-agent-example.workflow.js.map +1 -0
  35. package/dist/workflows/github-agent/templates/systemMessage.md +23 -0
  36. package/dist/workflows/github-agent/templates/welcomeMessage.md +10 -0
  37. package/dist/workflows/github-overview/github-overview-example.workflow.d.ts +96 -0
  38. package/dist/workflows/github-overview/github-overview-example.workflow.d.ts.map +1 -0
  39. package/dist/workflows/github-overview/github-overview-example.workflow.js +216 -0
  40. package/dist/workflows/github-overview/github-overview-example.workflow.js.map +1 -0
  41. package/dist/workflows/github-overview/templates/repoOverview.md +81 -0
  42. package/dist/workflows/google-calendar-summary/google-calendar-summary-example.workflow.d.ts +32 -0
  43. package/dist/workflows/google-calendar-summary/google-calendar-summary-example.workflow.d.ts.map +1 -0
  44. package/dist/workflows/google-calendar-summary/google-calendar-summary-example.workflow.js +113 -0
  45. package/dist/workflows/google-calendar-summary/google-calendar-summary-example.workflow.js.map +1 -0
  46. package/dist/workflows/google-calendar-summary/templates/calendarSummary.md +10 -0
  47. package/dist/workflows/google-workspace-agent/google-workspace-agent-example.ui.yaml +6 -0
  48. package/dist/workflows/google-workspace-agent/google-workspace-agent-example.workflow.d.ts +41 -0
  49. package/dist/workflows/google-workspace-agent/google-workspace-agent-example.workflow.d.ts.map +1 -0
  50. package/dist/workflows/google-workspace-agent/google-workspace-agent-example.workflow.js +187 -0
  51. package/dist/workflows/google-workspace-agent/google-workspace-agent-example.workflow.js.map +1 -0
  52. package/dist/workflows/google-workspace-agent/templates/calendarSummary.md +10 -0
  53. package/dist/workflows/google-workspace-agent/templates/systemMessage.md +24 -0
  54. package/dist/workflows/google-workspace-agent/templates/welcomeMessage.md +7 -0
  55. package/package.json +52 -0
  56. package/src/index.ts +7 -0
  57. package/src/oauth-examples.module.ts +30 -0
  58. package/src/shared/github/authenticate-github-task.tool.ts +70 -0
  59. package/src/shared/github/index.ts +1 -0
  60. package/src/shared/google/authenticate-google-task.tool.ts +72 -0
  61. package/src/shared/google/google-calendar-fetch-events.tool.ts +117 -0
  62. package/src/shared/google/index.ts +2 -0
  63. package/src/workflows/github-agent/github-agent-example.ui.yaml +6 -0
  64. package/src/workflows/github-agent/github-agent-example.workflow.ts +193 -0
  65. package/src/workflows/github-agent/templates/systemMessage.md +23 -0
  66. package/src/workflows/github-agent/templates/welcomeMessage.md +10 -0
  67. package/src/workflows/github-overview/github-overview-example.workflow.ts +223 -0
  68. package/src/workflows/github-overview/templates/repoOverview.md +81 -0
  69. package/src/workflows/google-calendar-summary/google-calendar-summary-example.workflow.ts +102 -0
  70. package/src/workflows/google-calendar-summary/templates/calendarSummary.md +10 -0
  71. package/src/workflows/google-workspace-agent/google-workspace-agent-example.ui.yaml +6 -0
  72. package/src/workflows/google-workspace-agent/google-workspace-agent-example.workflow.ts +147 -0
  73. package/src/workflows/google-workspace-agent/templates/calendarSummary.md +10 -0
  74. package/src/workflows/google-workspace-agent/templates/systemMessage.md +24 -0
  75. package/src/workflows/google-workspace-agent/templates/welcomeMessage.md +7 -0
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.GoogleWorkspaceAgentExampleWorkflow = void 0;
13
+ const node_path_1 = require("node:path");
14
+ const zod_1 = require("zod");
15
+ const common_1 = require("@loopstack/common");
16
+ const google_workspace_module_1 = require("@loopstack/google-workspace-module");
17
+ const llm_provider_module_1 = require("@loopstack/llm-provider-module");
18
+ const oauth_module_1 = require("@loopstack/oauth-module");
19
+ const authenticate_google_task_tool_1 = require("../../shared/google/authenticate-google-task.tool");
20
+ let GoogleWorkspaceAgentExampleWorkflow = class GoogleWorkspaceAgentExampleWorkflow extends common_1.BaseWorkflow {
21
+ llmGenerateText;
22
+ llmDelegateToolCalls;
23
+ llmUpdateToolResult;
24
+ authenticateGoogle;
25
+ googleCalendarListCalendars;
26
+ googleCalendarFetchEvents;
27
+ googleCalendarCreateEvent;
28
+ gmailSearchMessages;
29
+ gmailGetMessage;
30
+ gmailSendMessage;
31
+ gmailReplyToMessage;
32
+ googleDriveListFiles;
33
+ googleDriveGetFileMetadata;
34
+ googleDriveDownloadFile;
35
+ googleDriveUploadFile;
36
+ oAuth;
37
+ constructor(llmGenerateText, llmDelegateToolCalls, llmUpdateToolResult, authenticateGoogle, googleCalendarListCalendars, googleCalendarFetchEvents, googleCalendarCreateEvent, gmailSearchMessages, gmailGetMessage, gmailSendMessage, gmailReplyToMessage, googleDriveListFiles, googleDriveGetFileMetadata, googleDriveDownloadFile, googleDriveUploadFile, oAuth) {
38
+ super();
39
+ this.llmGenerateText = llmGenerateText;
40
+ this.llmDelegateToolCalls = llmDelegateToolCalls;
41
+ this.llmUpdateToolResult = llmUpdateToolResult;
42
+ this.authenticateGoogle = authenticateGoogle;
43
+ this.googleCalendarListCalendars = googleCalendarListCalendars;
44
+ this.googleCalendarFetchEvents = googleCalendarFetchEvents;
45
+ this.googleCalendarCreateEvent = googleCalendarCreateEvent;
46
+ this.gmailSearchMessages = gmailSearchMessages;
47
+ this.gmailGetMessage = gmailGetMessage;
48
+ this.gmailSendMessage = gmailSendMessage;
49
+ this.gmailReplyToMessage = gmailReplyToMessage;
50
+ this.googleDriveListFiles = googleDriveListFiles;
51
+ this.googleDriveGetFileMetadata = googleDriveGetFileMetadata;
52
+ this.googleDriveDownloadFile = googleDriveDownloadFile;
53
+ this.googleDriveUploadFile = googleDriveUploadFile;
54
+ this.oAuth = oAuth;
55
+ }
56
+ async setup(_state) {
57
+ await this.documentStore.save(llm_provider_module_1.LlmContextDocument, {
58
+ role: 'user',
59
+ text: this.render((0, node_path_1.join)(__dirname, 'templates', 'systemMessage.md')),
60
+ });
61
+ await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
62
+ role: 'assistant',
63
+ text: this.render((0, node_path_1.join)(__dirname, 'templates', 'welcomeMessage.md')),
64
+ });
65
+ }
66
+ async userMessage(_state, input) {
67
+ await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, { role: 'user', text: input.data });
68
+ }
69
+ async llmTurn(_state) {
70
+ const result = await this.llmGenerateText.call({}, {
71
+ config: {
72
+ provider: 'claude',
73
+ model: 'claude-sonnet-4-6',
74
+ system: `You are a helpful Google Workspace assistant with access to Calendar, Gmail, and Drive tools.
75
+ When a tool returns an unauthorized error, use authenticateGoogle to let the user sign in,
76
+ then retry. Be concise and format results using markdown.`,
77
+ tools: [
78
+ 'google_calendar_list_calendars',
79
+ 'google_calendar_fetch_events',
80
+ 'google_calendar_create_event',
81
+ 'gmail_search_messages',
82
+ 'gmail_get_message',
83
+ 'gmail_send_message',
84
+ 'gmail_reply_to_message',
85
+ 'google_drive_list_files',
86
+ 'google_drive_get_file_metadata',
87
+ 'google_drive_download_file',
88
+ 'google_drive_upload_file',
89
+ 'authenticate_google',
90
+ ],
91
+ },
92
+ });
93
+ this.assignState({ llmResult: result.data });
94
+ }
95
+ async executeToolCalls(state) {
96
+ const result = await this.llmDelegateToolCalls.call({
97
+ message: state.llmResult.message,
98
+ callback: { transition: 'toolResultReceived' },
99
+ });
100
+ this.assignState({ delegateResult: result.data });
101
+ }
102
+ hasToolCalls(state) {
103
+ return state.llmResult?.message.stopReason === 'tool_use';
104
+ }
105
+ async toolResultReceived(state, input) {
106
+ const result = await this.llmUpdateToolResult.call({
107
+ delegateResult: state.delegateResult,
108
+ completedTool: input,
109
+ });
110
+ this.assignState({ delegateResult: result.data });
111
+ }
112
+ allToolsCompleteTransition(_state) { }
113
+ allToolsComplete(state) {
114
+ return state.delegateResult?.allCompleted ?? false;
115
+ }
116
+ respond(_state) { }
117
+ };
118
+ exports.GoogleWorkspaceAgentExampleWorkflow = GoogleWorkspaceAgentExampleWorkflow;
119
+ __decorate([
120
+ (0, common_1.Transition)({ to: 'waiting_for_user' }),
121
+ __metadata("design:type", Function),
122
+ __metadata("design:paramtypes", [Object]),
123
+ __metadata("design:returntype", Promise)
124
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "setup", null);
125
+ __decorate([
126
+ (0, common_1.Transition)({ from: 'waiting_for_user', to: 'ready', wait: true, schema: zod_1.z.string() }),
127
+ __metadata("design:type", Function),
128
+ __metadata("design:paramtypes", [Object, Object]),
129
+ __metadata("design:returntype", Promise)
130
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "userMessage", null);
131
+ __decorate([
132
+ (0, common_1.Transition)({ from: 'ready', to: 'prompt_executed' }),
133
+ __metadata("design:type", Function),
134
+ __metadata("design:paramtypes", [Object]),
135
+ __metadata("design:returntype", Promise)
136
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "llmTurn", null);
137
+ __decorate([
138
+ (0, common_1.Transition)({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 }),
139
+ (0, common_1.Guard)('hasToolCalls'),
140
+ __metadata("design:type", Function),
141
+ __metadata("design:paramtypes", [Object]),
142
+ __metadata("design:returntype", Promise)
143
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "executeToolCalls", null);
144
+ __decorate([
145
+ (0, common_1.Transition)({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true, schema: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()) }),
146
+ __metadata("design:type", Function),
147
+ __metadata("design:paramtypes", [Object, Object]),
148
+ __metadata("design:returntype", Promise)
149
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "toolResultReceived", null);
150
+ __decorate([
151
+ (0, common_1.Transition)({ from: 'awaiting_tools', to: 'ready' }),
152
+ (0, common_1.Guard)('allToolsComplete'),
153
+ __metadata("design:type", Function),
154
+ __metadata("design:paramtypes", [Object]),
155
+ __metadata("design:returntype", void 0)
156
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "allToolsCompleteTransition", null);
157
+ __decorate([
158
+ (0, common_1.Transition)({ from: 'prompt_executed', to: 'waiting_for_user' }),
159
+ __metadata("design:type", Function),
160
+ __metadata("design:paramtypes", [Object]),
161
+ __metadata("design:returntype", void 0)
162
+ ], GoogleWorkspaceAgentExampleWorkflow.prototype, "respond", null);
163
+ exports.GoogleWorkspaceAgentExampleWorkflow = GoogleWorkspaceAgentExampleWorkflow = __decorate([
164
+ (0, common_1.Workflow)({
165
+ title: 'OAuth - Google Workspace Agent Example',
166
+ description: 'An interactive chat agent with access to Google Calendar, Gmail, and Google Drive. Handles OAuth automatically — the agent detects unauthorized errors and launches authentication on its own.',
167
+ name: 'google_workspace_agent_example',
168
+ widget: './google-workspace-agent-example.ui.yaml',
169
+ }),
170
+ __metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateTextTool,
171
+ llm_provider_module_1.LlmDelegateToolCallsTool,
172
+ llm_provider_module_1.LlmUpdateToolResultTool,
173
+ authenticate_google_task_tool_1.AuthenticateGoogleTask,
174
+ google_workspace_module_1.GoogleCalendarListCalendarsTool,
175
+ google_workspace_module_1.GoogleCalendarFetchEventsTool,
176
+ google_workspace_module_1.GoogleCalendarCreateEventTool,
177
+ google_workspace_module_1.GmailSearchMessagesTool,
178
+ google_workspace_module_1.GmailGetMessageTool,
179
+ google_workspace_module_1.GmailSendMessageTool,
180
+ google_workspace_module_1.GmailReplyToMessageTool,
181
+ google_workspace_module_1.GoogleDriveListFilesTool,
182
+ google_workspace_module_1.GoogleDriveGetFileMetadataTool,
183
+ google_workspace_module_1.GoogleDriveDownloadFileTool,
184
+ google_workspace_module_1.GoogleDriveUploadFileTool,
185
+ oauth_module_1.OAuthWorkflow])
186
+ ], GoogleWorkspaceAgentExampleWorkflow);
187
+ //# sourceMappingURL=google-workspace-agent-example.workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-workspace-agent-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/google-workspace-agent/google-workspace-agent-example.workflow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ Here are your upcoming events:
2
+
3
+ {{#each events}}
4
+
5
+ - **{{ this.summary }}** — {{ this.start }} to {{ this.end }}
6
+ {{/each}}
7
+
8
+ {{#unless events}}
9
+ No upcoming events found.
10
+ {{/unless}}
@@ -0,0 +1,24 @@
1
+ You are a helpful Google Workspace assistant. You have access to the user's
2
+ Google Calendar, Gmail, and Google Drive through the tools provided to you.
3
+
4
+ You can help with:
5
+
6
+ - **Calendar**: List calendars, fetch events, create new events
7
+ - **Gmail**: Search messages, read full emails, send new emails, reply to threads
8
+ - **Drive**: Search files, get file details, download/export files, upload files
9
+
10
+ When using date/time parameters, always use ISO 8601 format.
11
+
12
+ When a tool returns `{ error: "unauthorized" }` or `{ error: "401" }`, call the
13
+ `authenticateGoogle` tool with the required OAuth scopes to let the user sign in.
14
+ After authentication completes, retry the original request.
15
+
16
+ Common scopes:
17
+
18
+ - Calendar: https://www.googleapis.com/auth/calendar.events
19
+ - Gmail: https://www.googleapis.com/auth/gmail.modify
20
+ - Drive: https://www.googleapis.com/auth/drive
21
+
22
+ IMPORTANT: When using authenticateGoogle, it must be the ONLY tool call in your response.
23
+
24
+ Be concise and helpful. Format results clearly using markdown.
@@ -0,0 +1,7 @@
1
+ Hi! I'm your Google Workspace assistant. I can help you with:
2
+
3
+ - **Calendar** — list calendars, fetch events, create new events
4
+ - **Gmail** — search messages, read details, send and reply to emails
5
+ - **Drive** — browse files, view metadata, download and upload files
6
+
7
+ I'll handle Google sign-in automatically when needed. What would you like to do?
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@loopstack/oauth-examples",
3
+ "displayName": "Loopstack OAuth Examples",
4
+ "description": "Workflow examples for OAuth-protected integrations in Loopstack — GitHub repos overview, GitHub agent, Google Calendar summary, Google Workspace agent.",
5
+ "keywords": [
6
+ "loopstack",
7
+ "example",
8
+ "oauth",
9
+ "github",
10
+ "google",
11
+ "workflow"
12
+ ],
13
+ "version": "0.1.1",
14
+ "license": "MIT",
15
+ "author": {
16
+ "name": "Jakob Klippel",
17
+ "url": "https://www.linkedin.com/in/jakob-klippel/"
18
+ },
19
+ "main": "dist/index.js",
20
+ "types": "dist/index.d.ts",
21
+ "exports": {
22
+ ".": "./dist/index.js",
23
+ "./src/*": "./src/*"
24
+ },
25
+ "scripts": {
26
+ "build": "nest build",
27
+ "compile": "tsc --noEmit",
28
+ "format": "prettier --write .",
29
+ "lint": "eslint .",
30
+ "test": "vitest run --passWithNoTests",
31
+ "watch": "nest build --watch"
32
+ },
33
+ "dependencies": {
34
+ "@loopstack/claude-module": "*",
35
+ "@loopstack/common": "*",
36
+ "@loopstack/github-module": "*",
37
+ "@loopstack/google-workspace-module": "*",
38
+ "@loopstack/llm-provider-module": "*",
39
+ "@loopstack/oauth-module": "*",
40
+ "@nestjs/common": "^11.1.19",
41
+ "zod": "^4.3.6"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "src"
46
+ ],
47
+ "devDependencies": {
48
+ "vitest": "^4.1.6",
49
+ "@swc/core": "^1.15.33",
50
+ "unplugin-swc": "^1.5.9"
51
+ }
52
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './oauth-examples.module';
2
+ export * from './workflows/github-overview/github-overview-example.workflow';
3
+ export * from './workflows/github-agent/github-agent-example.workflow';
4
+ export * from './workflows/google-calendar-summary/google-calendar-summary-example.workflow';
5
+ export * from './workflows/google-workspace-agent/google-workspace-agent-example.workflow';
6
+ export * from './shared/github';
7
+ export * from './shared/google';
@@ -0,0 +1,30 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { ClaudeModule } from '@loopstack/claude-module';
3
+ import { StudioApp } from '@loopstack/common';
4
+ import { GitHubModule } from '@loopstack/github-module';
5
+ import { GoogleWorkspaceModule } from '@loopstack/google-workspace-module';
6
+ import { AuthenticateGitHubTask } from './shared/github/authenticate-github-task.tool';
7
+ import { AuthenticateGoogleTask } from './shared/google/authenticate-google-task.tool';
8
+ import { GoogleCalendarFetchEventsTool } from './shared/google/google-calendar-fetch-events.tool';
9
+ import { GithubAgentExampleWorkflow } from './workflows/github-agent/github-agent-example.workflow';
10
+ import { GithubOverviewExampleWorkflow } from './workflows/github-overview/github-overview-example.workflow';
11
+ import { GoogleCalendarSummaryExampleWorkflow } from './workflows/google-calendar-summary/google-calendar-summary-example.workflow';
12
+ import { GoogleWorkspaceAgentExampleWorkflow } from './workflows/google-workspace-agent/google-workspace-agent-example.workflow';
13
+
14
+ const WORKFLOWS = [
15
+ GithubOverviewExampleWorkflow,
16
+ GithubAgentExampleWorkflow,
17
+ GoogleCalendarSummaryExampleWorkflow,
18
+ GoogleWorkspaceAgentExampleWorkflow,
19
+ ];
20
+
21
+ @StudioApp({
22
+ title: 'OAuth Examples',
23
+ workflows: WORKFLOWS,
24
+ })
25
+ @Module({
26
+ imports: [ClaudeModule, GitHubModule, GoogleWorkspaceModule],
27
+ providers: [AuthenticateGitHubTask, AuthenticateGoogleTask, GoogleCalendarFetchEventsTool, ...WORKFLOWS],
28
+ exports: [AuthenticateGitHubTask, AuthenticateGoogleTask, GoogleCalendarFetchEventsTool, ...WORKFLOWS],
29
+ })
30
+ export class OAuthExamplesModule {}
@@ -0,0 +1,70 @@
1
+ import { Logger } from '@nestjs/common';
2
+ import { z } from 'zod';
3
+ import { BaseTool, Tool, ToolCallOptions, ToolEnvelope } from '@loopstack/common';
4
+ import type { RunContext } from '@loopstack/common';
5
+ import { OAuthWorkflow } from '@loopstack/oauth-module';
6
+
7
+ const AuthenticateGitHubTaskInputSchema = z
8
+ .object({
9
+ scopes: z.array(z.string()).describe('The OAuth scopes to request (e.g. repo, user, workflow, read:org)'),
10
+ callback: z
11
+ .object({
12
+ transition: z.string(),
13
+ metadata: z.record(z.string(), z.unknown()).optional(),
14
+ })
15
+ .optional(),
16
+ })
17
+ .strict();
18
+
19
+ type AuthenticateGitHubTaskInput = z.infer<typeof AuthenticateGitHubTaskInputSchema>;
20
+
21
+ export type AuthenticateGitHubTaskResult = { workflowId: string; mode: string; [key: string]: unknown } | string;
22
+
23
+ @Tool({
24
+ name: 'authenticate_github',
25
+ description:
26
+ 'Launches GitHub OAuth authentication. Shows the user a sign-in prompt to authorize access to GitHub. ' +
27
+ 'Use this when a GitHub tool returns an "unauthorized" error. ' +
28
+ 'Pass the required OAuth scopes for the GitHub APIs you need access to. ' +
29
+ 'IMPORTANT: When using this tool, it must be the ONLY tool call in your response. Do not combine it with other tool calls.',
30
+ schema: AuthenticateGitHubTaskInputSchema,
31
+ })
32
+ export class AuthenticateGitHubTask extends BaseTool<
33
+ AuthenticateGitHubTaskInput,
34
+ object,
35
+ AuthenticateGitHubTaskResult
36
+ > {
37
+ private readonly logger = new Logger(AuthenticateGitHubTask.name);
38
+
39
+ constructor(private readonly oAuthWorkflow: OAuthWorkflow) {
40
+ super();
41
+ }
42
+
43
+ protected async handle(
44
+ args: AuthenticateGitHubTaskInput,
45
+ ctx: RunContext,
46
+ options?: ToolCallOptions,
47
+ ): Promise<ToolEnvelope<AuthenticateGitHubTaskResult>> {
48
+ const result = await this.oAuthWorkflow.run(
49
+ { provider: 'github', scopes: args.scopes },
50
+ { callback: options?.callback ?? args.callback, show: 'inline', label: 'GitHub authentication required' },
51
+ );
52
+
53
+ return {
54
+ data: { ...result, mode: 'async' },
55
+ pending: { workflowId: result.workflowId },
56
+ };
57
+ }
58
+
59
+ async complete(result: Record<string, unknown>): Promise<ToolEnvelope<AuthenticateGitHubTaskResult>> {
60
+ const status = result.status as string | undefined;
61
+ if (status === 'failed' || status === 'canceled') {
62
+ const detail = (result.errorMessage as string | undefined) ?? `Sub-workflow ${status}`;
63
+ const message = `GitHub authentication ${status}: ${detail}`;
64
+ return { data: message, error: message };
65
+ }
66
+ return {
67
+ data: 'GitHub authentication completed successfully. You can now use GitHub tools.',
68
+ };
69
+ }
70
+ }
@@ -0,0 +1 @@
1
+ export * from './authenticate-github-task.tool';
@@ -0,0 +1,72 @@
1
+ import { Logger } from '@nestjs/common';
2
+ import { z } from 'zod';
3
+ import { BaseTool, Tool, ToolCallOptions, ToolEnvelope } from '@loopstack/common';
4
+ import type { RunContext } from '@loopstack/common';
5
+ import { OAuthWorkflow } from '@loopstack/oauth-module';
6
+
7
+ const AuthenticateGoogleTaskInputSchema = z
8
+ .object({
9
+ scopes: z
10
+ .array(z.string())
11
+ .describe('The OAuth scopes to request (e.g. https://www.googleapis.com/auth/calendar.events)'),
12
+ callback: z
13
+ .object({
14
+ transition: z.string(),
15
+ metadata: z.record(z.string(), z.unknown()).optional(),
16
+ })
17
+ .optional(),
18
+ })
19
+ .strict();
20
+
21
+ type AuthenticateGoogleTaskInput = z.infer<typeof AuthenticateGoogleTaskInputSchema>;
22
+
23
+ export type AuthenticateGoogleTaskResult = { workflowId: string; mode: string; [key: string]: unknown } | string;
24
+
25
+ @Tool({
26
+ name: 'authenticate_google',
27
+ description:
28
+ 'Launches Google OAuth authentication. Shows the user a sign-in prompt to authorize access to Google services. ' +
29
+ 'Use this when a Google tool returns an "unauthorized" error. ' +
30
+ 'Pass the required OAuth scopes for the Google APIs you need access to. ' +
31
+ 'IMPORTANT: When using this tool, it must be the ONLY tool call in your response. Do not combine it with other tool calls.',
32
+ schema: AuthenticateGoogleTaskInputSchema,
33
+ })
34
+ export class AuthenticateGoogleTask extends BaseTool<
35
+ AuthenticateGoogleTaskInput,
36
+ object,
37
+ AuthenticateGoogleTaskResult
38
+ > {
39
+ private readonly logger = new Logger(AuthenticateGoogleTask.name);
40
+
41
+ constructor(private readonly oAuthWorkflow: OAuthWorkflow) {
42
+ super();
43
+ }
44
+
45
+ protected async handle(
46
+ args: AuthenticateGoogleTaskInput,
47
+ ctx: RunContext,
48
+ options?: ToolCallOptions,
49
+ ): Promise<ToolEnvelope<AuthenticateGoogleTaskResult>> {
50
+ const result = await this.oAuthWorkflow.run(
51
+ { provider: 'google', scopes: args.scopes },
52
+ { callback: options?.callback ?? args.callback, show: 'inline', label: 'Google authentication required' },
53
+ );
54
+
55
+ return {
56
+ data: { ...result, mode: 'async' },
57
+ pending: { workflowId: result.workflowId },
58
+ };
59
+ }
60
+
61
+ async complete(result: Record<string, unknown>): Promise<ToolEnvelope<AuthenticateGoogleTaskResult>> {
62
+ const status = result.status as string | undefined;
63
+ if (status === 'failed' || status === 'canceled') {
64
+ const detail = (result.errorMessage as string | undefined) ?? `Sub-workflow ${status}`;
65
+ const message = `Google authentication ${status}: ${detail}`;
66
+ return { data: message, error: message };
67
+ }
68
+ return {
69
+ data: 'Google authentication completed successfully. You can now use Google Workspace tools.',
70
+ };
71
+ }
72
+ }
@@ -0,0 +1,117 @@
1
+ import { Logger } from '@nestjs/common';
2
+ import { z } from 'zod';
3
+ import { BaseTool, Tool, ToolEnvelope } from '@loopstack/common';
4
+ import type { RunContext } from '@loopstack/common';
5
+ import { OAuthTokenStore } from '@loopstack/oauth-module';
6
+
7
+ const GoogleCalendarFetchEventsSchema = z
8
+ .object({
9
+ timeMin: z.string(),
10
+ timeMax: z.string(),
11
+ calendarId: z.string().default('primary'),
12
+ })
13
+ .strict();
14
+
15
+ type GoogleCalendarFetchEventsArgs = z.infer<typeof GoogleCalendarFetchEventsSchema>;
16
+
17
+ export type GoogleCalendarFetchEventsResult = {
18
+ error?: string;
19
+ message?: string;
20
+ events?: { id: string; summary: string; start: string | undefined; end: string | undefined }[];
21
+ };
22
+
23
+ interface GoogleCalendarEvent {
24
+ id: string;
25
+ summary: string;
26
+ start: { dateTime?: string; date?: string };
27
+ end: { dateTime?: string; date?: string };
28
+ }
29
+
30
+ interface GoogleCalendarListResponse {
31
+ items: GoogleCalendarEvent[];
32
+ }
33
+
34
+ @Tool({
35
+ name: 'google_calendar_fetch_events',
36
+ description: 'Fetches events from Google Calendar. Returns { error: "unauthorized" } if no valid token is available.',
37
+ schema: GoogleCalendarFetchEventsSchema,
38
+ })
39
+ export class GoogleCalendarFetchEventsTool extends BaseTool<
40
+ GoogleCalendarFetchEventsArgs,
41
+ object,
42
+ GoogleCalendarFetchEventsResult
43
+ > {
44
+ private readonly logger = new Logger(GoogleCalendarFetchEventsTool.name);
45
+
46
+ constructor(private readonly tokenStore: OAuthTokenStore) {
47
+ super();
48
+ }
49
+
50
+ protected async handle(
51
+ args: GoogleCalendarFetchEventsArgs,
52
+ ctx: RunContext,
53
+ ): Promise<ToolEnvelope<GoogleCalendarFetchEventsResult>> {
54
+ const accessToken = await this.tokenStore.getValidAccessToken(ctx.userId, 'google');
55
+
56
+ if (!accessToken) {
57
+ return {
58
+ data: {
59
+ error: 'unauthorized',
60
+ message: 'No valid Google token found. Please authenticate first.',
61
+ },
62
+ error: 'No valid Google token found. Please authenticate first.',
63
+ };
64
+ }
65
+
66
+ const calendarId = args.calendarId || 'primary';
67
+ const params = new URLSearchParams({
68
+ timeMin: args.timeMin,
69
+ timeMax: args.timeMax,
70
+ singleEvents: 'true',
71
+ orderBy: 'startTime',
72
+ });
73
+
74
+ const response = await fetch(
75
+ `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(calendarId)}/events?${params.toString()}`,
76
+ {
77
+ headers: { Authorization: `Bearer ${accessToken}` },
78
+ },
79
+ );
80
+
81
+ if (response.status === 401 || response.status === 403) {
82
+ this.logger.warn(`Google Calendar API returned ${response.status} for user ${ctx.userId}`);
83
+ return {
84
+ data: {
85
+ error: '401',
86
+ message: 'Google token was rejected. Please re-authenticate.',
87
+ },
88
+ error: 'Google token was rejected. Please re-authenticate.',
89
+ };
90
+ }
91
+
92
+ if (!response.ok) {
93
+ const body = await response.text();
94
+ this.logger.error(`Google Calendar API error: ${response.status} ${body}`);
95
+ console.log('api_error', response.statusText);
96
+ return {
97
+ data: {
98
+ error: 'api_error',
99
+ message: `Google Calendar API error: ${response.statusText}`,
100
+ },
101
+ error: `Google Calendar API error: ${response.statusText}`,
102
+ };
103
+ }
104
+
105
+ const data: GoogleCalendarListResponse = (await response.json()) as GoogleCalendarListResponse;
106
+ const events = data.items.map((event) => ({
107
+ id: event.id,
108
+ summary: event.summary,
109
+ start: event.start.dateTime || event.start.date,
110
+ end: event.end.dateTime || event.end.date,
111
+ }));
112
+
113
+ return {
114
+ data: { events },
115
+ };
116
+ }
117
+ }
@@ -0,0 +1,2 @@
1
+ export * from './authenticate-google-task.tool';
2
+ export * from './google-calendar-fetch-events.tool';
@@ -0,0 +1,6 @@
1
+ widget: prompt-input
2
+ enabledWhen:
3
+ - waiting_for_user
4
+ options:
5
+ transition: userMessage
6
+ label: Send Message