Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 44 additions & 33 deletions .github/scripts/csat.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ const CONSTANT_VALUES = {
QUESTION: 'question',
JAVASCRIPT: 'javascript',
STATUS_IN_PROGRESS: 'status/in-progress',
NEEDS_REVIEW: 'needs review'
NEEDS_REVIEW: 'needs review',
},
STATE: { CLOSED: 'closed' },
STATE: {CLOSED: 'closed'},
},
MODULE: {
CSAT: {
YES: 'Yes',
NO: 'No',
BASE_URL: 'https://docs.google.com/forms/d/e/1FAIpQLSeuqIP8vcNJv0Gv84ruyxmvrMQElhB2L0saRtuapK7c28QMWQ/viewform?',
BASE_URL:
'https://docs.google.com/forms/d/e/1FAIpQLSeuqIP8vcNJv0Gv84ruyxmvrMQElhB2L0saRtuapK7c28QMWQ/viewform?',
SATISFACTION_PARAM: 'entry.2064764942=',
ISSUEID_PARAM: '&entry.666097176=',
MSG: 'Are you satisfied with the resolution of your issue?',
}
}
},
},
};

/**
Expand All @@ -37,37 +38,47 @@ const CONSTANT_VALUES = {
* context Information about the workflow run.
* @return {null}
*/
module.exports = async ({ github, context }) => {
const issue = context.payload.issue.html_url;

// Check if any label matches (case-insensitive) the supported CSAT labels.
const supportedLabels = Object.values(CONSTANT_VALUES.GLOBALS.LABELS);
const hasMatchingLabel = context.payload.issue.labels.some(label => {
const name = label.name.toLowerCase();
return supportedLabels.some(supportedLabel => name.includes(supportedLabel));
});
module.exports = async ({github, context}) => {
const issue = context.payload.issue.html_url;

if (hasMatchingLabel) {
console.log(`Posting CSAT survey for issue =${issue}`);
const baseUrl = CONSTANT_VALUES.MODULE.CSAT.BASE_URL;
// Check if any label matches (case-insensitive) the supported CSAT labels.
const supportedLabels = Object.values(CONSTANT_VALUES.GLOBALS.LABELS);
const hasMatchingLabel = context.payload.issue.labels.some((label) => {
const name = label.name.toLowerCase();
return supportedLabels.some((supportedLabel) =>
name.includes(supportedLabel),
);
});

const yesCsat = `<a href="${baseUrl + CONSTANT_VALUES.MODULE.CSAT.SATISFACTION_PARAM +
CONSTANT_VALUES.MODULE.CSAT.YES +
CONSTANT_VALUES.MODULE.CSAT.ISSUEID_PARAM + encodeURIComponent(issue)}"> ${CONSTANT_VALUES.MODULE.CSAT.YES}</a>`;
if (hasMatchingLabel) {
console.log(`Posting CSAT survey for issue =${issue}`);
const baseUrl = CONSTANT_VALUES.MODULE.CSAT.BASE_URL;

const noCsat = `<a href="${baseUrl + CONSTANT_VALUES.MODULE.CSAT.SATISFACTION_PARAM +
CONSTANT_VALUES.MODULE.CSAT.NO +
CONSTANT_VALUES.MODULE.CSAT.ISSUEID_PARAM + encodeURIComponent(issue)}"> ${CONSTANT_VALUES.MODULE.CSAT.NO}</a>`;
const yesCsat = `<a href="${
baseUrl +
CONSTANT_VALUES.MODULE.CSAT.SATISFACTION_PARAM +
CONSTANT_VALUES.MODULE.CSAT.YES +
CONSTANT_VALUES.MODULE.CSAT.ISSUEID_PARAM +
encodeURIComponent(issue)
}"> ${CONSTANT_VALUES.MODULE.CSAT.YES}</a>`;

const comment = CONSTANT_VALUES.MODULE.CSAT.MSG + '\n' + yesCsat + '\n' +
noCsat + '\n';
const issueNumber = context.issue.number ?? context.payload.issue.number;
const noCsat = `<a href="${
baseUrl +
CONSTANT_VALUES.MODULE.CSAT.SATISFACTION_PARAM +
CONSTANT_VALUES.MODULE.CSAT.NO +
CONSTANT_VALUES.MODULE.CSAT.ISSUEID_PARAM +
encodeURIComponent(issue)
}"> ${CONSTANT_VALUES.MODULE.CSAT.NO}</a>`;

await github.rest.issues.createComment({
issue_number: issueNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
}
const comment =
CONSTANT_VALUES.MODULE.CSAT.MSG + '\n' + yesCsat + '\n' + noCsat + '\n';
const issueNumber = context.issue.number ?? context.payload.issue.number;

await github.rest.issues.createComment({
issue_number: issueNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment,
});
}
};
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
node_modules/
dev/src/browser
api-reference/
24 changes: 12 additions & 12 deletions .prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
*/

export default {
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "preserve",
"bracketSpacing": false,
"trailingComma": "all",
"arrowParens": "always",
"bracketSameLine": true,
"endOfLine": "auto",
"plugins": ["prettier-plugin-organize-imports"],
'printWidth': 80,
'tabWidth': 2,
'useTabs': false,
'semi': true,
'singleQuote': true,
'quoteProps': 'preserve',
'bracketSpacing': false,
'trailingComma': 'all',
'arrowParens': 'always',
'bracketSameLine': true,
'endOfLine': 'auto',
'plugins': ['prettier-plugin-organize-imports'],
};
2 changes: 1 addition & 1 deletion core/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function build({
buildOptions.banner = {
js:
(buildOptions.banner?.js || '') +
`import {createRequire as topLevelCreateRequire} from 'module';\nconst require = topLevelCreateRequire(import.meta.url);`,
`import {createRequire as topLevelCreateRequire} from 'node:module';\nconst require = topLevelCreateRequire(import.meta.url);`,
};
}

Expand Down
10 changes: 8 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,16 @@ export default defineConfig([
},
},
{
// A `.cjs` file is CommonJS by definition, so `require()` is correct there.
// CommonJS sources, where `require()` is correct: `.cjs` by extension, plus
// the `.js` fixtures whose nearest package.json declares
// `"type": "commonjs"` or omits `"type"` altogether.
// `tseslint.configs.recommended` carries no `files` filter and sets
// `sourceType: 'module'` for every file, which this restores.
files: ['**/*.cjs'],
files: [
'**/*.cjs',
'tests/integration/build_setup/js_commonjs/**/*.js',
'tests/integration/app_loader/app_js/**/*.js',
],
languageOptions: {sourceType: 'commonjs'},
rules: {'@typescript-eslint/no-require-imports': 'off'},
},
Expand Down
2 changes: 1 addition & 1 deletion integrations/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function build({
buildOptions.banner = {
js:
(buildOptions.banner?.js || '') +
`import {createRequire as topLevelCreateRequire} from 'module';\nconst require = topLevelCreateRequire(import.meta.url);`,
`import {createRequire as topLevelCreateRequire} from 'node:module';\nconst require = topLevelCreateRequire(import.meta.url);`,
};
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"ts:check": "tsc --noEmit",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"format": "prettier \"**/*.ts\" --write",
"format:check": "prettier \"**/*.ts\" --check",
"format": "prettier \"**/*.{ts,js,cjs,mjs}\" --write",
"format:check": "prettier \"**/*.{ts,js,cjs,mjs}\" --check",
"docs": "npm run docs:clean && npm run docs:generate && npm run docs:serve",
"docs:clean": "rm -rf ./api-reference",
"docs:generate": "typedoc",
Expand Down
6 changes: 4 additions & 2 deletions scripts/auto-assignment.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

export default async function autoAssign({ github, context }) {
export default async function autoAssign({github, context}) {
console.log('Auto-assignment script started');

let issueNumber;
Expand All @@ -23,7 +23,9 @@ export default async function autoAssign({ github, context }) {
issueNumber = context.payload.pull_request.number;

// Skip PRs from forks to prevent 403 errors
if (context.repo.owner !== context.payload.pull_request.head.repo.owner.login) {
if (
context.repo.owner !== context.payload.pull_request.head.repo.owner.login
) {
console.log('PR from fork detected: skipping auto-assignment');
return;
}
Expand Down
1 change: 0 additions & 1 deletion tests/integration/app_loader/app_js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

/* eslint-disable @typescript-eslint/no-require-imports */
const {App, BaseLlm, LlmAgent, LLMRegistry} = require('@google/adk');
const {createModelContent} = require('@google/genai');
const fs = require('node:fs/promises');
Expand Down
38 changes: 38 additions & 0 deletions tests/integration/build_setup/build_banner_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Pins the module specifier in the `createRequire` banner that the build
* scripts inject into every emitted ESM and web artifact. The specifier lives
* inside a template literal in a build script, so it is plain text to ESLint
* rather than an `ImportDeclaration`, and no lint rule can guard it; a bare
* `'module'` here would be shadowable by a userland package of that name in a
* consumer's dependency tree, breaking the artifact before any ADK code runs.
*/

import {readFile} from 'node:fs/promises';
import {join} from 'node:path';
import {describe, expect, it} from 'vitest';

const dirname = process.cwd();

const BANNER_IMPORT =
"import {createRequire as topLevelCreateRequire} from 'node:module';";
const BARE_SPECIFIER = "from 'module'";

describe('Build banner', () => {
describe.each([
['core', 'core/build.js'],
['integrations', 'integrations/build.js'],
])('%s', (_workspace: string, buildScript: string) => {
it('imports the module builtin with the node: protocol', async () => {
const contents = await readFile(join(dirname, buildScript), 'utf8');

expect(contents).toContain(BANNER_IMPORT);
expect(contents).not.toContain(BARE_SPECIFIER);
});
});
});
48 changes: 48 additions & 0 deletions tests/integration/build_setup/esm_build_banner_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Pins the `createRequire` banner on the *published* artifacts rather than on
* the build script that emits it, so the assertion still holds if the banner
* moves, is rewritten, or stops being emitted at all.
*
* Requires `npm run build` to have run first -- the same precondition the rest
* of the `integration` project already has, since the build_setup fixtures
* resolve `@google/adk` and `@google/adk-devtools` through their `dist`
* directories. CI runs `npm run build` before the test step.
*/

import {readFile} from 'node:fs/promises';
import {join} from 'node:path';
import {describe, expect, it} from 'vitest';

const dirname = process.cwd();

const EXPECTED_BANNER_FIRST_LINE =
"import {createRequire as topLevelCreateRequire} from 'node:module';";

describe.each(['core', 'integrations'])('%s ESM build banner', (pkg) => {
it.each(['esm', 'web'])(
'prefixes the createRequire import with node: in dist/%s',
async (target) => {
const source = await readFile(
join(dirname, pkg, 'dist', target, 'index.js'),
'utf8',
);

expect(source.split('\n')[0]).toBe(EXPECTED_BANNER_FIRST_LINE);
},
);

it('does not inject the createRequire banner into the cjs target', async () => {
const source = await readFile(
join(dirname, pkg, 'dist', 'cjs', 'index.js'),
'utf8',
);

expect(source).not.toContain('topLevelCreateRequire');
});
});
6 changes: 3 additions & 3 deletions tests/integration/build_setup/js_commonjs/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ const {
LogLevel,
BaseLlm,
LLMRegistry,
} = require('@google/adk'); // eslint-disable-line @typescript-eslint/no-require-imports
const {createModelContent, GenerateContentResponse} = require('@google/genai'); // eslint-disable-line @typescript-eslint/no-require-imports
const {MockLlmConnection} = require('../../mock_llm_connection'); // eslint-disable-line @typescript-eslint/no-require-imports
} = require('@google/adk');
const {createModelContent, GenerateContentResponse} = require('@google/genai');
const {MockLlmConnection} = require('../../mock_llm_connection');

setLogLevel(LogLevel.DEBUG);

Expand Down
4 changes: 2 additions & 2 deletions tests/integration/build_setup/js_commonjs/db_init_check.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const {DatabaseSessionService} = require('@google/adk'); // eslint-disable-line @typescript-eslint/no-require-imports
const {MikroORM} = require('@mikro-orm/core'); // eslint-disable-line @typescript-eslint/no-require-imports
const {DatabaseSessionService} = require('@google/adk');
const {MikroORM} = require('@mikro-orm/core');

MikroORM.init = async () => {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const {AdkApiServer} = require('@google/adk-devtools'); // eslint-disable-line @typescript-eslint/no-require-imports
const {AdkApiServer} = require('@google/adk-devtools');

console.log('Importing AdkApiServer works');
if (typeof AdkApiServer !== 'function') {
Expand Down