- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5.5k
302 ai new components #18829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
302 ai new components #18829
Conversation
| The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
 | 
| Thank you so much for submitting this! We've added it to our backlog to review, and our team has been notified. | 
| Thanks for submitting this PR! When we review PRs, we follow the Pipedream component guidelines. If you're not familiar, here's a quick checklist: 
 | 
| WalkthroughRefactored the 302.AI app module to implement a unified API client pattern with model discovery and completion handling. Added five new action modules (chat, chat-with-functions, classify-items, summarize-text, create-embeddings) with shared configuration helpers, constants, and common base classes. Updated build configuration and dependency manifest. Changes
 Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes The refactoring introduces a new API client pattern requiring careful review of authentication flow, request handling, and model discovery implementation. Five heterogeneous action modules with distinct logic paths (chat, classification, summarization, embeddings, function calling) each demand separate reasoning. Common helpers establish pluggable lifecycle hooks that multiple actions depend on, necessitating validation of contracts and data flow across the inheritance chain. The mix of app-level architectural changes, multiple new files, and JSON schema/response format handling increases overall complexity. Poem
 Pre-merge checks and finishing touches❌ Failed checks (1 warning)
 ✅ Passed checks (3 passed)
 ✨ Finishing touches
 🧪 Generate unit tests (beta)
 Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (18)
mdc_memory.mdc (1)
1-1: Avoid duplicating memory notes (dedupe with components/memory.mdc).Keep a single source of truth to prevent drift; link the other to it.
components/memory.mdc (1)
1-1: Consolidate with mdc_memory.mdc.Unify these two memory files; retain one and reference it from the other. Based on learnings.
components/_302_ai/302_ai_components.mdc (1)
8-12: Align examples with guidance and fix minor doc issues.
- Replace the axios($) example with one that calls app._makeRequest to match your own rule.
- Fix typos: “detaults” → “defaults”, “appropiate” → “appropriate”, “enpoint” → “endpoint”.
- Complete the “create-completion” sentence (name at least one legacy model class or say “models that support the /completions endpoint”).
Apply this example tweak:
- return await axios($, { - url: `https://api.302.ai/v1/models`, - headers: { - Authorization: `Bearer ${this._302_ai.$auth.api_key}`, - }, - }) + return await this._302_ai._makeRequest({ + $, + path: "/models", + method: "GET", + })Also applies to: 33-51, 76-79
components/_302_ai/actions/common/common-helper.mjs (1)
32-46: Solid shared run() flow.Message construction + _getCommonArgs + app.createChatCompletion looks clean and reusable.
Optionally add a guard for empty system/user messages to fail fast with a clearer error.
components/_302_ai/_302_ai.app.mjs (1)
20-33: Model filter may exclude valid chat models; ensure options are inclusive. Also preserve convenience fields in _makeCompletion.
- The regex filter (gpt|claude|gemini|llama|mistral|deepseek) risks hiding valid 302.AI chat models. Prefer capability flags from the API (if available) or don’t filter at all.
- In _makeCompletion, spread data first so generated_text/generated_message aren’t overwritten by the API payload.- return models - .filter((model) => model.id.match(/gpt|claude|gemini|llama|mistral|deepseek/gi)) - .map((model) => ({ + return models + // TODO: Prefer an official capability field (e.g., model.capabilities.includes("chat")) + // For now, don't filter to avoid excluding valid models. + .map((model) => ({ label: model.id, value: model.id, })); @@ - return { - generated_text, - generated_message, - ...data, - }; + return { + ...data, + generated_text, + generated_message, + };
If 302.AI exposes a “type/capabilities” field on models, we can refine the filter accordingly.
Also applies to: 101-105
components/_302_ai/actions/common/constants.mjs (1)
1-14: LGTM, consider freezing to avoid accidental mutation.The constants look good. To harden at runtime, freeze them to prevent accidental mutation.
const CHAT_RESPONSE_FORMAT = { @@ }; const SUMMARIZE_LENGTH = [ @@ ]; +Object.freeze(CHAT_RESPONSE_FORMAT); +Object.freeze(SUMMARIZE_LENGTH);Also applies to: 16-26
components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (5)
63-73: Enable selecting a specific function cleanly in the UI.Current prop only allows "auto" / "required" options, but code and docs imply arbitrary function names. Add an explicit "function" option and a companion input for the function name.
toolChoice: { type: "string", label: "Tool Choice", - description: "- **auto**: The model decides whether and how many functions to call.\n- **required**: The model must call one or more functions.\n- **function_name**: Enter a custom function name to force the model to call this specific function.", + description: "- **auto**: The model decides whether and how many functions to call.\n- **required**: The model must call one or more functions.\n- **function**: Force the model to call a specific function name you provide below.", optional: true, default: "auto", options: [ "auto", "required", + "function", ], }, @@ - additionalProps() { + additionalProps() { const props = {}; + if (this.toolChoice === "function") { + props.toolChoiceFunctionName = { + type: "string", + label: "Function Name", + description: "Exact name of the function to force the model to call.", + }; + } + if (this.responseFormat === constants.CHAT_RESPONSE_FORMAT.JSON_SCHEMA.value) { props.jsonSchema = { type: "string", label: "JSON Schema", description: "Define the schema that the model's output must adhere to.", }; } return props; }, @@ - } else { - data.tool_choice = { - type: "function", - name: this.toolChoice, - }; - } + } else if (this.toolChoiceFunctionName) { + data.tool_choice = { + type: "function", + function: { name: this.toolChoiceFunctionName }, + }; + }Please confirm whether the Pipedream UI allows free-form values when
optionsare present. If not, this change is required to unlock forced function calling.Also applies to: 116-128, 174-183
74-90: Use a boolean for Parallel Function Calling.The current string "1"/"0" pattern is brittle. Prefer a boolean prop and map directly.
- parallelToolCalls: { - type: "string", - label: "Parallel Function Calling", - description: "Allow or prevent the model to call multiple functions in a single turn", - optional: true, - default: "1", - options: [ - { - label: "Enabled", - value: "1", - }, - { - label: "Disabled", - value: "0", - }, - ], - }, + parallelToolCalls: { + type: "boolean", + label: "Parallel Function Calling", + description: "Allow the model to call multiple functions in a single turn", + optional: true, + default: true, + }, @@ - parallel_tool_calls: parseInt(this.parallelToolCalls) === 1, + parallel_tool_calls: !!this.parallelToolCalls,Also applies to: 147-149
15-26: Reuse common props and numeric parsing; avoid partial duplication.This action reimplements
maxTokens/temperatureand omits other supported params (topP,n,stop, penalties,user). Importcommonand spread...common.props; builddatafrom...this._getCommonArgs()instead of ad-hoc parsing.-import _302_ai from "../../_302_ai.app.mjs"; -import constants from "../common/constants.mjs"; +import _302_ai from "../../_302_ai.app.mjs"; +import common from "../common/common.mjs"; +import constants from "../common/constants.mjs"; @@ export default { - name: "Chat using Functions", + ...common, + name: "Chat using Functions", @@ props: { _302_ai, modelId: { @@ - maxTokens: { - label: "Max Tokens", - description: "The maximum number of tokens to generate in the completion.", - type: "string", - optional: true, - }, - temperature: { - label: "Temperature", - description: "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.", - type: "string", - optional: true, - }, + ...common.props, @@ - const data = { - model: this.modelId, + const data = { + ...this._getCommonArgs(), messages, parallel_tool_calls: !!this.parallelToolCalls, tools: [], }; @@ - if (this.maxTokens) { - data.max_tokens = parseInt(this.maxTokens); - } - - if (this.temperature) { - data.temperature = parseFloat(this.temperature); - } + // common props already handled by _getCommonArgs()Also applies to: 91-102, 144-154, 155-157
159-166: Validate tools schema early.Guard against malformed tool definitions to fail fast with actionable errors.
if (typeof functions === "string") { try { functions = JSON.parse(functions); } catch (error) { throw new Error("Invalid JSON format in the provided Functions Schema"); } } - if (Array.isArray(functions)) { - data.tools.push(...functions); - } else { - data.tools.push(functions); - } + const toArray = Array.isArray(functions) ? functions : [functions]; + for (const t of toArray) { + if (!t || t.type !== "function" || !t.function || !t.function.name) { + throw new Error("Each tool must have type \"function\" and a function { name, ... }"); + } + } + data.tools.push(...toArray);Also applies to: 168-173
103-114: Consider supporting JSON Object response format here too.Unless 302.AI forbids it with tools, you can expose
json_objectalongsidetextandjson_schema.responseFormat: { type: "string", label: "Response Format", description: "- **Text**: Returns unstructured text output.\n- **JSON Schema**: Enables you to define a specific structure for the model's output using a JSON schema.", options: [ - constants.CHAT_RESPONSE_FORMAT.TEXT.value, - constants.CHAT_RESPONSE_FORMAT.JSON_SCHEMA.value, + constants.CHAT_RESPONSE_FORMAT.TEXT.value, + constants.CHAT_RESPONSE_FORMAT.JSON_OBJECT.value, + constants.CHAT_RESPONSE_FORMAT.JSON_SCHEMA.value, ], default: constants.CHAT_RESPONSE_FORMAT.TEXT.value, optional: true, reloadProps: true, },Also applies to: 185-197
components/_302_ai/actions/summarize-text/summarize-text.mjs (2)
41-43: Handle empty/whitespace input early.Guard against accidental empty
textto avoid spending tokens and returning empty summaries.userMessage() { - return `Summarize the following text${this.maxLength()}: ${this.text}`; + const body = (this.text || "").trim(); + if (!body) { + throw new Error("Text is required to summarize."); + } + return `Summarize the following text${this.maxLength()}: ${body}`; },
44-62: Safer handling when no choices are returned.Add a defensive check to avoid accessing
choices[0]when the API returns no choices.formatOutput({ messages, response, }) { if (!messages || !response) { throw new Error("Invalid API output, please reach out to https://pipedream.com/support"); } + if (!Array.isArray(response.choices) || response.choices.length === 0) { + throw new Error("No choices returned by the API."); + } const output = { messages, }; const n = this.n ? parseInt(this.n) : 1; if (n > 1) { output.summaries = response.choices?.map(({ message }) => message.content); } else { output.summary = response.choices?.[0]?.message?.content; } return output; },components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (4)
37-42: Improve messages prop UX to accept structured messages too.
type: "string[]"restricts object inputs, but the code accepts objects. Either add an alternateobject[]prop or switch toobject[]and accept JSON strings inside.messages: { label: "Prior Message History", - type: "string[]", + type: "string[]", description: "Because the models have no memory of past chat requests, all relevant information must be supplied via the conversation. You can provide an array of messages from prior conversations here. **Formats supported:** 1) Plain strings with role prefix (e.g., `User: Hello` or `Assistant: Hi there`), 2) JSON strings (e.g., `{\"role\": \"user\", \"content\": \"Hello\"}`), 3) Plain strings without prefix (defaults to user role).", optional: true, },Optionally add:
+additionalProps() { + const props = {}; + // existing JSON Schema block... + props.messagesObjects = { + type: "object[]", + label: "Prior Message History (objects)", + description: "Alternative to the string array: supply structured messages like { role, content }.", + optional: true, + }; + return props; +},
107-114: Always include systemInstructions if provided (unless already present).Currently, system instructions are skipped when
messagesare provided. Include them if none of the provided messages has rolesystem.- } else { - if (this.systemInstructions) { - messages.push({ - "role": "system", - "content": this.systemInstructions, - }); - } - } + } + if (this.systemInstructions) { + const hasSystem = messages.some((m) => m?.role?.toLowerCase?.() === "system"); + if (!hasSystem) { + messages.unshift({ + role: "system", + content: this.systemInstructions, + }); + } + }Also applies to: 65-106
150-158: Parse assistant content for JSON Object responses too.Apply JSON parsing when response format is
json_objectas well asjson_schema.- if (this.responseFormat === constants.CHAT_RESPONSE_FORMAT.JSON_SCHEMA.value) { + if ( + this.responseFormat === constants.CHAT_RESPONSE_FORMAT.JSON_SCHEMA.value || + this.responseFormat === constants.CHAT_RESPONSE_FORMAT.JSON_OBJECT.value + ) { for (const choice of response.choices) { try { choice.message.content = JSON.parse(choice.message.content); } catch { - console.log(`Unable to parse JSON: ${choice.message.content}`); + console.debug?.("Unable to parse JSON content for choice", { content: choice.message.content }); } } }
164-168: Guard against missing assistant message on concat.Avoid appending
undefinedwhen no choices are returned.return { original_messages: messages, - original_messages_with_assistant_response: messages.concat(response.choices[0]?.message), + original_messages_with_assistant_response: response.choices?.[0]?.message + ? messages.concat(response.choices[0].message) + : messages.slice(), ...response, };components/_302_ai/actions/common/common.mjs (1)
81-81: Drop unnecessary async from _getChatArgs.No awaits inside; make it synchronous.
- async _getChatArgs() { + _getChatArgs() {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
- pnpm-lock.yamlis excluded by- !**/pnpm-lock.yaml
📒 Files selected for processing (17)
- .husky/pre-push(1 hunks)
- components/_302_ai/302_ai_components.mdc(1 hunks)
- components/_302_ai/_302_ai.app.mjs(1 hunks)
- components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs(1 hunks)
- components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs(1 hunks)
- components/_302_ai/actions/classify-items/classify-items.mjs(1 hunks)
- components/_302_ai/actions/common/common-helper.mjs(1 hunks)
- components/_302_ai/actions/common/common.mjs(1 hunks)
- components/_302_ai/actions/common/constants.mjs(1 hunks)
- components/_302_ai/actions/create-embeddings/create-embeddings.mjs(1 hunks)
- components/_302_ai/actions/summarize-text/summarize-text.mjs(1 hunks)
- components/_302_ai/package.json(2 hunks)
- components/memory.mdc(1 hunks)
- components/pipedream-context.mdc(1 hunks)
- components/ticketsauce/ticketsauce_components.mdc(1 hunks)
- mdc_memory.mdc(1 hunks)
- mdc_pipedream-context.mdc(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-15T22:01:11.472Z
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#18362
File: components/leonardo_ai/actions/generate-image/generate-image.mjs:103-105
Timestamp: 2025-09-15T22:01:11.472Z
Learning: In Pipedream components, pipedream/platform's axios implementation automatically excludes undefined values from HTTP requests, so there's no need to manually check for truthiness before including properties in request payloads.
Applied to files:
- mdc_memory.mdc
- components/memory.mdc
🧬 Code graph analysis (8)
components/_302_ai/actions/classify-items/classify-items.mjs (3)
components/_302_ai/actions/common/common-helper.mjs (2)
messages(33-42)
response(48-51)components/_302_ai/actions/common/common.mjs (1)
messages(82-82)components/_302_ai/actions/summarize-text/summarize-text.mjs (2)
output(50-52)
n(53-55)
components/_302_ai/actions/create-embeddings/create-embeddings.mjs (1)
components/_302_ai/_302_ai.app.mjs (3)
data(82-86)
data(91-91)
data(97-97)
components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (4)
components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (4)
props(117-117)
messages(130-130)
data(144-149)
response(199-202)components/_302_ai/actions/common/common-helper.mjs (3)
messages(33-42)
data(43-47)
response(48-51)components/_302_ai/actions/common/common.mjs (2)
messages(82-82)
responseFormat(96-112)components/_302_ai/_302_ai.app.mjs (3)
data(82-86)
data(91-91)
data(97-97)
components/_302_ai/actions/summarize-text/summarize-text.mjs (5)
components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (2)
messages(130-130)
response(199-202)components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (2)
messages(65-65)
response(145-148)components/_302_ai/actions/common/common-helper.mjs (2)
messages(33-42)
response(48-51)components/_302_ai/actions/common/common.mjs (1)
messages(82-82)components/_302_ai/actions/classify-items/classify-items.mjs (2)
output(67-69)
n(70-72)
components/_302_ai/_302_ai.app.mjs (5)
components/_302_ai/actions/common/common.mjs (1)
args(56-78)components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (1)
data(144-149)components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (1)
data(139-143)components/_302_ai/actions/common/common-helper.mjs (1)
data(43-47)components/_302_ai/actions/create-embeddings/create-embeddings.mjs (1)
data(63-66)
components/_302_ai/actions/common/common-helper.mjs (4)
components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (3)
messages(130-130)
data(144-149)
response(199-202)components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (3)
messages(65-65)
data(139-143)
response(145-148)components/_302_ai/actions/common/common.mjs (1)
messages(82-82)components/_302_ai/_302_ai.app.mjs (3)
data(82-86)
data(91-91)
data(97-97)
components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (4)
components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (4)
props(54-54)
messages(65-65)
data(139-143)
response(145-148)components/_302_ai/actions/common/common-helper.mjs (3)
messages(33-42)
data(43-47)
response(48-51)components/_302_ai/actions/common/common.mjs (1)
messages(82-82)components/_302_ai/_302_ai.app.mjs (3)
data(82-86)
data(91-91)
data(97-97)
components/_302_ai/actions/common/common.mjs (3)
components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs (1)
messages(130-130)components/_302_ai/actions/chat-with-302-ai/chat-with-302-ai.mjs (2)
messages(65-65)
responseFormat(121-137)components/_302_ai/actions/common/common-helper.mjs (1)
messages(33-42)
🔇 Additional comments (6)
components/pipedream-context.mdc (1)
1-32: Clarify the purpose and completeness of this documentation file.This file appears to be a guidance/context document for Pipedream component development, but its role in this PR is unclear. Additionally, the "Sources (Webhooks)" section (starting at line 27) appears truncated—only the section header and a bullet list begin are shown, without the full guidance content.
Before merging, clarify:
- Is this file intended to be part of the PR deliverables, or is it just contextual guidance for reviewers?
- If it's a deliverable, ensure the "Sources (Webhooks)" section and any other sections are complete.
- Verify that this documentation aligns with and complements the 302.AI components being added (chat, chat-with-functions, classify-items, summarize-text, create-embeddings).
Note: The guidance itself aligns well with the review checklist provided in the PR comments (e.g., component key naming, reusable propDefinitions, ConfigurationError usage). However, this document should not duplicate or replace component-specific documentation or inline code comments.
components/ticketsauce/ticketsauce_components.mdc (1)
1-52: Scope mismatch claim cannot be verified — but implementation is incomplete.The original review comment claims this file should not be in a PR for "302 ai new components." However, I cannot verify the PR scope since metadata lookup failed. That said, both 302.AI and TicketSauce component directories coexist in the repository, suggesting they may be intended together.
The actual concern is that the TicketSauce implementation is incomplete:
ticketsauce.app.mjsis a stub with no methods (compare to_302_ai.app.mjswhich has full propDefinitions,_makeRequest, and helpers)- No action implementation files exist in
components/ticketsauce/actions/(312.AI has 8 action files; TicketSauce has zero)
package.jsonspecifies version"0.0.1", but the specification file itself (lines 11–31) mandates"0.1.0"per guidelines- The
.mdcspecification exists with detailed action definitions (lines 54–748), but corresponding.mjsimplementations are missingThe specification file (ticketsauce_components.mdc) is well-structured and follows the same pattern as 302.AI components, but the JavaScript/TypeScript implementation has not been generated from it.
mdc_pipedream-context.mdc (3)
1-3: Clarify the purpose and location of this documentation file.This is a Markdown documentation/context file rather than component code. The YAML front matter (
alwaysApply: true) suggests it's metadata for a specific development environment or tool. Please clarify:
- Whether this file should be committed to the repository or if it's for IDE/context purposes only
- If it should be committed, where it belongs in the repository structure (e.g.,
/docs,/CONTRIBUTING.md, etc.)- What system interprets the
alwaysApplydirective
1-32: Remove.mdcfile from repository or consolidate into formal developer documentation.The file
mdc_pipedream-context.mdcis a multi-document context file (.mdcformat designed for AI tools like Cursor), not standard developer documentation. While it's currently committed to the repository, it should not be:
Root-level
.mdcfiles are not documentation:.mdcformat is for AI model context, not repository-facing guides. If this content is valuable for developers, convert to.mdformat.
Content should consolidate with existing docs: The component guidelines (file structure, naming conventions, code patterns, webhook sources) overlap with existing documentation. Integrate into
CONTRIBUTING.mdor create a dedicatedcomponents/GUIDELINES.mdif component-specific guidance warrants a separate file.
Decision needed:
- If meant as developer documentation: Convert to
.mdand merge intoCONTRIBUTING.mdunder a "Pipedream Component Development" section- If meant as AI context only: Remove from repository (use
.gitignorefor.mdcfiles at root)
21-22: No changes needed — the documented axios behavior is verified.The guidance stating that
@pipedream/platform's axios "filters out undefined values, no need to check parameters individually before including them" is accurate. This behavior is confirmed by verified learning from PR #18362 (Sept 15, 2025), where the same pattern was validated in the leonardo_ai component. The repository uses version ^1.5.1, which supports this automatic filtering.components/_302_ai/package.json (1)
15-17: Verify SDK version fragmentation is acceptable.The monorepo has mixed
@pipedream/platformversions (ranging from^0.9.0to^3.1.0). The proposed^3.1.0aligns with current usage in several components but does not address existing version fragmentation. Confirm this is intentional or consider a standardization effort.
| . "$(dirname "$0")/_/husky.sh" | ||
|  | ||
| npx pnpm install -r | ||
| npx pnpm install --frozen-lockfile | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify if -r flag is needed and confirm intended behavior change.
This change replaces what was presumably -r (recursive/workspace install) with --frozen-lockfile (strict lockfile validation). These flags serve different purposes and the change has significant implications:
- 
Monorepo concern: If this is a monorepo with workspaces, removing -rmeans dependencies won't be installed across all workspace projects, potentially breaking the build.
- 
Behavior change: --frozen-lockfilefails immediately ifpackage.jsonandpnpm-lock.yamlare out of sync, which changes the workflow from "install → check → friendly reminder" to "fail fast." This makes lines 6-9 somewhat redundant since an out-of-sync lockfile would have already failed at line 4.
- 
Developer experience: Developers who legitimately add dependencies will now encounter a cryptic pnpm error instead of the helpful "please commit the file" message. 
- 
PR scope: This change appears unrelated to the stated PR objectives (adding 302.AI components). 
Run this script to verify if this is a monorepo requiring -r:
🏁 Script executed:
#!/bin/bash
# Check if this is a pnpm workspace/monorepo
# Look for pnpm-workspace.yaml
if [ -f "pnpm-workspace.yaml" ]; then
  echo "=== pnpm-workspace.yaml exists ==="
  cat pnpm-workspace.yaml
fi
# Check root package.json for workspace patterns
if [ -f "package.json" ]; then
  echo -e "\n=== Checking package.json for workspace indicators ==="
  jq -r 'if .workspaces then "workspaces field: " + (.workspaces | tostring) else "No workspaces field" end' package.json 2>/dev/null || echo "Could not parse package.json"
fi
# Count packages in components directory (common workspace pattern)
echo -e "\n=== Checking for multiple package.json files (workspace indicator) ==="
fd -t f '^package\.json$' | head -20Length of output: 907
Now let me verify the original command and check for patterns of pnpm usage with -r in the codebase:
Now let me check for pnpm usage patterns in the codebase:
Let me check the pnpm configuration and view the full pre-push file:
Based on my verification:
Restore the -r flag: Change npx pnpm install --frozen-lockfile to npx pnpm install -r --frozen-lockfile
This change removes the -r (recursive) flag from the pnpm install command, which is critical for a monorepo. Inside a workspace, pnpm install installs all dependencies in all the projects, but this behavior can be disabled by setting the recursive-install setting to false. By removing the explicit -r flag, the pre-push hook now relies on implicit configuration defaults rather than explicit control.
The -r flag runs a command in every project of a workspace when used with install. The proper command for a monorepo should be npx pnpm install -r --frozen-lockfile to ensure both recursive installation across all workspace packages AND strict lockfile validation. These flags serve complementary purposes—not competing ones—and should both be present.
🤖 Prompt for AI Agents
.husky/pre-push around line 4: the pnpm install command dropped the recursive
flag, which can break monorepo installs when recursive-install is disabled;
change the command back to include -r so it reads npx pnpm install -r
--frozen-lockfile to force recursive installation across workspace packages
while still enforcing the frozen lockfile.
| if (this.toolChoice) { | ||
| if (this.toolChoice === "auto" || this.toolChoice === "required") { | ||
| data.tool_choice = this.toolChoice; | ||
| } else { | ||
| data.tool_choice = { | ||
| type: "function", | ||
| name: this.toolChoice, | ||
| }; | ||
| } | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
tool_choice object shape is likely incorrect (will be rejected by API).
When forcing a specific function, the payload should nest the function name, e.g. { type: "function", function: { name: "..." } } (OpenAI-compatible schema).
-      } else {
-        data.tool_choice = {
-          type: "function",
-          name: this.toolChoice,
-        };
-      }
+      } else {
+        data.tool_choice = {
+          type: "function",
+          function: {
+            name: this.toolChoice,
+          },
+        };
+      }🌐 Web query:
Does 302.AI's chat completions API expect tool_choice in the OpenAI-compatible shape `{ type: "function", function: { name: "..." } }`?
💡 Result:
Yes — 302.AI’s chat/completions endpoint uses the OpenAI-compatible tool/function shape. You can pass tool_choice as an object like {"type":"function","function":{"name":"my_function"}}. [1][2]
Sources:
- 302.AI docs (notes that the API is compatible with OpenAI format). [1]
- OpenAI / OpenAPI-style doc showing tool_choice object shape {"type":"function","function":{"name":"my_function"}}. [2]
tool_choice object shape is incorrect and will be rejected by the API.
302.AI's chat completions API uses the OpenAI-compatible tool_choice format, requiring { type: "function", function: { name: "..." } }. The current code incorrectly nests the function name directly under type instead of under a function property.
      } else {
        data.tool_choice = {
          type: "function",
-         name: this.toolChoice,
+         function: {
+           name: this.toolChoice,
+         },
        };
      }Fix the object structure to nest the function name under a function property.
🤖 Prompt for AI Agents
In components/_302_ai/actions/chat-using-functions/chat-using-functions.mjs
around lines 174 to 183, the tool_choice object currently sets { type:
"function", name: this.toolChoice } which is the wrong shape; change it to {
type: "function", function: { name: this.toolChoice } } so the function name is
nested under a function property; update the assignment accordingly and ensure
other code consuming data.tool_choice expects the new shape.
| return "Please only categorize items into the specific categories, and no others. Output a valid JSON string — an array of objects, where each object has the following properties: item, category. Do not return any English text other than the JSON, either before or after the JSON. I need to parse the response as JSON, and parsing will fail if you return any English before or after the JSON"; | ||
| }, | ||
| userMessage() { | ||
| return `Categorize each of the following items:\n\n${this.items.join("\n")}\n\ninto one of the following categories:\n\n${this.categories.join("\n")}\n\n${this.outputFormat()}}`; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix prompt typo and harden parsing of assistant output.
- Remove stray “}” at end of userMessage.
- Guard when choices/content is missing; don’t iterate undefined; throw a clear error if no content was returned.
- When n == 1 and parsing fails, avoid returning undefined.
-      return `Categorize each of the following items:\n\n${this.items.join("\n")}\n\ninto one of the following categories:\n\n${this.categories.join("\n")}\n\n${this.outputFormat()}}`;
+      return `Categorize each of the following items:\n\n${this.items.join("\n")}\n\ninto one of the following categories:\n\n${this.categories.join("\n")}\n\n${this.outputFormat()}`;
@@
-      const responses = response.choices?.map(({ message }) => message.content);
-      const categorizations = [];
-      for (const response of responses) {
+      const contents = Array.isArray(response.choices)
+        ? response.choices.map((c) => c?.message?.content).filter(Boolean)
+        : [];
+      if (contents.length === 0) {
+        throw new Error("No assistant content returned. Please try again or contact https://pipedream.com/support");
+      }
+      const categorizations = [];
+      for (const content of contents) {
         try {
-          categorizations.push(JSON.parse(response));
+          categorizations.push(JSON.parse(content));
         } catch (err) {
-          console.log("Failed to parse output, assistant returned malformed JSON");
+          console.log("Failed to parse output, assistant returned malformed JSON");
         }
       }
@@
-      if (n > 1) {
-        output.categorizations = categorizations;
-      } else {
-        output.categorizations = categorizations[0];
-      }
+      output.categorizations = n > 1 ? categorizations : (categorizations[0] ?? null);Also applies to: 58-66, 70-77
🤖 Prompt for AI Agents
In components/_302_ai/actions/classify-items/classify-items.mjs around lines 47,
58-66 and 70-77, remove the stray closing brace at the end of the user message
template (the trailing "}") and harden parsing of the assistant response: before
iterating make sure response.choices exists and each choice has
.message?.content (or .text) and throw a clear, descriptive Error if no content
was returned; when n == 1 and parsing of the structured output fails, do not
return undefined — instead fall back to returning the raw assistant content (or
throw a clear parse error if fallback is unacceptable), and ensure loops use
safe defaults (e.g., empty arrays) to avoid iterating undefined.
| _getCommonArgs() { | ||
| const args = { | ||
| model: this.modelId, | ||
| temperature: this.temperature | ||
| ? parseFloat(this.temperature) | ||
| : undefined, | ||
| top_p: this.topP | ||
| ? parseFloat(this.topP) | ||
| : undefined, | ||
| n: this.n | ||
| ? parseInt(this.n) | ||
| : undefined, | ||
| stop: this.stop, | ||
| presence_penalty: this.presencePenalty | ||
| ? parseFloat(this.presencePenalty) | ||
| : undefined, | ||
| frequency_penalty: this.frequencyPenalty | ||
| ? parseFloat(this.frequencyPenalty) | ||
| : undefined, | ||
| max_tokens: this.maxTokens | ||
| ? parseInt(this.maxTokens) | ||
| : undefined, | ||
| user: this.user, | ||
| }; | ||
| return args; | ||
| }, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Sanitize numeric props to avoid sending NaN to the API.
If users pass non-numeric strings, current code will set fields to NaN. Only include numeric fields when finite.
   _getCommonArgs() {
-      const args = {
-        model: this.modelId,
-        temperature: this.temperature
-          ? parseFloat(this.temperature)
-          : undefined,
-        top_p: this.topP
-          ? parseFloat(this.topP)
-          : undefined,
-        n: this.n
-          ? parseInt(this.n)
-          : undefined,
-        stop: this.stop,
-        presence_penalty: this.presencePenalty
-          ? parseFloat(this.presencePenalty)
-          : undefined,
-        frequency_penalty: this.frequencyPenalty
-          ? parseFloat(this.frequencyPenalty)
-          : undefined,
-        max_tokens: this.maxTokens
-          ? parseInt(this.maxTokens)
-          : undefined,
-        user: this.user,
-      };
+      const num = (v) => {
+        const n = Number(v);
+        return Number.isFinite(n) ? n : undefined;
+      };
+      const args = {
+        model: this.modelId,
+        temperature: num(this.temperature),
+        top_p: num(this.topP),
+        n: Number.isInteger(num(this.n)) ? Number(num(this.n)) : undefined,
+        stop: this.stop,
+        presence_penalty: num(this.presencePenalty),
+        frequency_penalty: num(this.frequencyPenalty),
+        max_tokens: Number.isInteger(num(this.maxTokens)) ? Number(num(this.maxTokens)) : undefined,
+        user: this.user,
+      };
       return args;
     },🏁 Script executed:
#!/bin/bash
# Scan repo for other direct parseInt/parseFloat on props that may leak NaN.
rg -nP 'parse(Int|Float)\s*\(\s*this\.' -C2Length of output: 61641
Based on the scan results, the issue identified in the review comment is valid and widespread across the codebase. The current pattern (this.property ? parseFloat/parseInt()) does not prevent NaN values when non-numeric strings are passed.
However, I notice the proposed diff has a minor inefficiency. Let me verify the exact current implementation to provide the most accurate rewritten comment:<!-- [scratchpad_update]
[task verify_fix_correctness]
Confirmed: Number.isFinite is the correct approach. Research shows:
- Number.isFinite catches NaN, Infinity, and -Infinity in one check
- For parsed values: num(this.temperature) already applies Number() conversion
- For integers: Number.isInteger() is used correctly to validate parsed result
[observations]
- Proposed diff uses: Number.isInteger(num(this.n)) ? Number(num(this.n)) : undefined
- This calls num() twice (inefficient)
- Optimization: Could extract the result to a variable or simplify logic
- However, the proposed fix IS functionally correct, just redundant
[analysis]
The review comment identifies a real, valid issue. The proposed diff correctly solves it using Number.isFinite.
Minor inefficiency in integer handling (double evaluation) but functionally sound.
Scan confirmed systemic issue across ~35 files.
[done]
Verified approach is correct. Ready to finalize rewritten comment.
[scratchpad_end] -->
Based on my verification of the scan results and testing patterns, the review comment correctly identifies the vulnerability. Number.isFinite() checks that a given value is a number, and the number is neither positive Infinity, negative Infinity, nor NaN. The current code using truthiness checks alone will fail to catch NaN values.
Fix NaN leakage in numeric field parsing — validate after conversion.
Current code uses truthiness to check for values before parsing, but this doesn't prevent NaN. For example, "abc" is truthy; parseFloat("abc") returns NaN. This NaN will be sent to the API, causing unexpected failures.
Only include numeric fields when they are finite numbers:
_getCommonArgs() {
  const num = (v) => {
    const n = Number(v);
    return Number.isFinite(n) ? n : undefined;
  };
  const args = {
    model: this.modelId,
    temperature: num(this.temperature),
    top_p: num(this.topP),
    n: Number.isInteger(num(this.n)) ? num(this.n) : undefined,
    stop: this.stop,
    presence_penalty: num(this.presencePenalty),
    frequency_penalty: num(this.frequencyPenalty),
    max_tokens: Number.isInteger(num(this.maxTokens)) ? num(this.maxTokens) : undefined,
    user: this.user,
  };
  return args;
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| _getCommonArgs() { | |
| const args = { | |
| model: this.modelId, | |
| temperature: this.temperature | |
| ? parseFloat(this.temperature) | |
| : undefined, | |
| top_p: this.topP | |
| ? parseFloat(this.topP) | |
| : undefined, | |
| n: this.n | |
| ? parseInt(this.n) | |
| : undefined, | |
| stop: this.stop, | |
| presence_penalty: this.presencePenalty | |
| ? parseFloat(this.presencePenalty) | |
| : undefined, | |
| frequency_penalty: this.frequencyPenalty | |
| ? parseFloat(this.frequencyPenalty) | |
| : undefined, | |
| max_tokens: this.maxTokens | |
| ? parseInt(this.maxTokens) | |
| : undefined, | |
| user: this.user, | |
| }; | |
| return args; | |
| }, | |
| _getCommonArgs() { | |
| const num = (v) => { | |
| const n = Number(v); | |
| return Number.isFinite(n) ? n : undefined; | |
| }; | |
| const args = { | |
| model: this.modelId, | |
| temperature: num(this.temperature), | |
| top_p: num(this.topP), | |
| n: Number.isInteger(num(this.n)) ? num(this.n) : undefined, | |
| stop: this.stop, | |
| presence_penalty: num(this.presencePenalty), | |
| frequency_penalty: num(this.frequencyPenalty), | |
| max_tokens: Number.isInteger(num(this.maxTokens)) ? num(this.maxTokens) : undefined, | |
| user: this.user, | |
| }; | |
| return args; | |
| }, | 
🤖 Prompt for AI Agents
In components/_302_ai/actions/common/common.mjs around lines 55-80, the current
truthy checks (e.g. this.temperature ? parseFloat(...) : undefined) allow NaN
through when non-numeric strings are passed; change each numeric field to parse
once into a local variable, validate with Number.isFinite (for floats) or
Number.isInteger (for ints) and only set the arg when the parsed value is valid,
otherwise set undefined; do this for temperature, topP, n, presencePenalty,
frequencyPenalty, and maxTokens to avoid double parsing and NaN leakage.
|  | ||
| export default { | ||
| name: "Create Embeddings", | ||
| version: "0.0.1", | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect “token” length validation; sync action version.
- element.length measures characters, not tokens → false positives vs 8192 tokens. Either implement real tokenization or remove the pre-check and rely on API errors with a clear message.
- Bump action version to 0.1.0 to match the package.
Apply:
-  version: "0.0.1",
+  version: "0.1.0",
@@
-    // Confirm no element is more than 8192 tokens in length
-    for (const [ i, element, ] of this.input.entries()) {
-      if (element.length > 8192) {
-        throw new ConfigurationError(`Element #${i} is more than 8192 tokens in length. Each input must not exceed 8192 tokens in length.`);
-      }
-    }
+    // Rely on API to enforce token limits; surface a clearer error if it fails.
+    // (Character length != token length; a naive check would reject valid inputs.)Also applies to: 53-61
🤖 Prompt for AI Agents
In components/_302_ai/actions/create-embeddings/create-embeddings.mjs around
line 6 (and also apply the same change to lines 53-61), the code incorrectly
uses element.length (character count) to validate against an 8192-token limit
and also has the action version set to "0.0.1"; remove the character-length
pre-check entirely (or replace it with a proper tokenizer if you choose to
implement token counting) so we rely on the API to enforce actual token limits
and return clear error messages, and update the version string to "0.1.0" to
match the package.
| Write the actions for the TicketSauce app. | ||
|  | ||
| General guidelines: | ||
| - Avoid manual truthiness checks for optional parameters, as @pipedream/platform utilities (@pipedream/axios) automatically exclude undefined values. | ||
| - Make sure to wrap API calls with the _makeRequest method. All actions methods need to call the _makeRequest methods. No actions method should call axios directly. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
File format and intent unclear — specification document rather than implementation.
Lines 4–52 contain guidelines, example code snippets, and best practices, but this file does not include the actual JavaScript/TypeScript component implementations. The .mdc format suggests this is a specification or prompt document to guide development, not production code itself.
Please clarify:
- Is this .mdcfile intended to be committed to the repository, or is it an intermediate artifact?
- Where are the actual component implementation files (.mjsor.jsfiles) for the TicketSauce actions?
- Should this spec be converted to actual runnable component code before merging?
🏁 Script executed:
#!/bin/bash
# Find all .mdc files to understand their purpose and usage pattern
echo "=== All .mdc files in repository ==="
fd -e mdc -type f
echo -e "\n=== TicketSauce-related files (.mjs, .js, .ts, .mdc) ==="
fd -i ticketsauce -type f
echo -e "\n=== Directory structure for components/ticketsauce ==="
find components/ticketsauce -type f 2>/dev/null | head -20
echo -e "\n=== Full content of the .mdc file under review ==="
cat components/ticketsauce/ticketsauce_components.mdc 2>/dev/nullLength of output: 30549
🏁 Script executed:
#!/bin/bash
# Check the ticketsauce.app.mjs file to understand dependencies
echo "=== Content of ticketsauce.app.mjs ==="
cat components/ticketsauce/ticketsauce.app.mjs
echo -e "\n=== Content of ticketsauce package.json ==="
cat components/ticketsauce/package.json
echo -e "\n=== Check for .mdc documentation in repo root/docs ==="
find . -maxdepth 3 -type f \( -name "README*" -o -name "*mdc*" \) 2>/dev/null | grep -v node_modules | head -20
echo -e "\n=== Search for references to ticketsauce actions in the codebase ==="
rg -i "ticketsauce.*get-events|ticketsauce.*get-orders" --type js --type mjs 2>/dev/null | head -10Length of output: 1439
Implementation incomplete — specification exists but no component files are present.
The .mdc file is a specification/prompt document (following the pattern used in other components like _302_ai_components.mdc), not production code. However, the critical issue is that:
- No action component files exist — The spec defines five actions (get-events, get-event-details, get-orders, get-order-details, get-ticket-checkin-ids) with detailed requirements, but no corresponding .mjsimplementation files are present.
- App stub is incomplete — ticketsauce.app.mjscontains only minimal authentication scaffolding with emptypropDefinitions.
- Missing dependencies — package.jsonomits required dependencies (@pipedream/platform, form-data) specified in the.mdcguidelines.
Before merging, implement the five action components as .mjs files (e.g., get-events.mjs, get-event-details.mjs, etc.) following the spec in the .mdc file, and update package.json with the required dependencies.
🤖 Prompt for AI Agents
In components/ticketsauce/ticketsauce_components.mdc around lines 4 to 8: the
spec defines five actions but there are no corresponding .mjs action files, the
app stub (ticketsauce.app.mjs) has empty propDefinitions, and package.json is
missing required dependencies; implement five action components (get-events.mjs,
get-event-details.mjs, get-orders.mjs, get-order-details.mjs,
get-ticket-checkin-ids.mjs) following the .mdc spec, ensure every action uses
this._makeRequest for HTTP calls (do not call axios directly), rely on
@pipedream/platform utilities so you do not manually filter undefined params,
update ticketsauce.app.mjs to include proper auth and propDefinitions referenced
by the actions and export/register the actions, and add @pipedream/platform and
form-data to package.json dependencies.
| get-events | ||
| Prompt | ||
| Get a list of all events owned by the authenticated account. | ||
|  | ||
| -When you come up for the description for this component follow format: <component description>. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#list-of-events) | ||
| - Here are the parameters for the related list events API endpoint, use as a basis for props: | ||
| ``` | ||
| partner_id | ||
| string optional | ||
| Including this ID will limit the result set to the specific partner. | ||
|  | ||
| organization_id | ||
| string optional | ||
| Including this ID will limit the result set to the specific organization. | ||
|  | ||
| start_after | ||
| string optional | ||
| Only retrieve events that start AFTER the specified UTC date (format: YYYY-MM-DD). | ||
|  | ||
| start_before | ||
| string optional | ||
| Only retrieve events that start BEFORE the specified UTC date (format: YYYY-MM-DD). | ||
|  | ||
| start_phrase | ||
| string optional | ||
| A string representing the date to pull events that start __. Possible values are: today, yesterday, tomorrow, this_week, this_weekend, next_week, next_weekend, this_month, next_month | ||
|  | ||
| end_after | ||
| string optional | ||
| Only retrieve events that end AFTER the specified UTC date (format: YYYY-MM-DD). | ||
|  | ||
| end_before | ||
| string optional | ||
| Only retrieve events that end BEFORE the specified UTC date (format: YYYY-MM-DD). | ||
|  | ||
| created_after | ||
| string optional | ||
| Only retrieve events that were created AFTER the specified UTC date (format: YYYY-MM-DD). | ||
|  | ||
| created_before | ||
| string optional | ||
| Only retrieve events that were created BEFORE the specified UTC date (format: YYYY-MM-DD). | ||
|  | ||
| active_only | ||
| boolean optional | ||
| Leaving this as true will restrict retrieved events to only ‘active’ events. Setting to false will allow the retrieval of both active and inactive events. | ||
| Default: | ||
| true | ||
|  | ||
| inactive_only | ||
| boolean optional | ||
| Setting to true will restrict retrieved events to only ‘inactive’ events. | ||
| Default: | ||
| false | ||
|  | ||
| privacy_type | ||
| string optional | ||
| By default, this will restrict events to only those that are public. Changing to ‘all’ will remove all restriction, or changing to ‘unlisted’ will make it only pull those events that are set to unlisted. | ||
| Default: | ||
| public | ||
|  | ||
| sort_by | ||
| string optional | ||
| Which field to sort by. By default (‘date’), will sort events by their start date. Other options are ‘name’ (event name) or ‘city’ (the city where the event is located). | ||
| Default: | ||
| date | ||
|  | ||
| sort_dir | ||
| string optional | ||
| Which direction you’d like to sort - either ascending (‘asc’ - the default) or descending (‘desc’). | ||
| Default: | ||
| asc | ||
|  | ||
| include_performers | ||
| string optional | ||
| Returns any associated performers/artists with an event | ||
|  | ||
| Default: | ||
| false | ||
| ``` | ||
|  | ||
| get-event-details | ||
| Prompt | ||
| Get details for a specified event. | ||
|  | ||
| -When you come up for the description for this component following format: <component description>. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#event-details) | ||
| - Here are the parameters for the related API endpoint, use as a basis for props: | ||
| ``` | ||
| id_or_slug | ||
| path parameter, string required | ||
|  | ||
| photos | ||
| query string parameter, integer optional | ||
| Whether or not to return the event’s photo gallery records. | ||
| Default: | ||
| 0 | ||
|  | ||
| include_performers | ||
| query string parameter, string optional | ||
| Returns any associated performers/artists with the event. | ||
| Default: | ||
| false | ||
| ``` | ||
| -for the prop related to id_or_slug use async options so users can select an event. | ||
| -as referece examples for async options you can use those found in apps zendesk, guru, etsy and recently you helped me come up with async options for prop imageId in generate-motion.mjs of leonardo ai app. | ||
| -when returning the context object, if there are no more options to return, simply return an empty object {} | ||
| -here is the response example for "list events" endpoint for you to come up with logic on how to implement async options for the prop related to id_or_slug | ||
| ``` | ||
| [ | ||
| { | ||
| "Event": { | ||
| "active": true, | ||
| "address": "1221 Saint James Street", | ||
| "address2": "", | ||
| "city": "Philadelphia", | ||
| "country": "United States", | ||
| "created": "2025-06-26 02:40:59", | ||
| "custom_id": null, | ||
| "show_start": true, | ||
| "show_end": false, | ||
| "end": "2029-03-01 23:45:00", | ||
| "end_utc": "2029-03-02 04:45:00", | ||
| "featured": false, | ||
| "id": "685cb33b-0dc8-462d-ae5b-00410a1e60d3", | ||
| "location": "Voyeur Nightclub", | ||
| "latitude": "39.948357", | ||
| "longitude": "-75.161697", | ||
| "map_zoom": "13", | ||
| "modified": "2025-09-16 22:08:06", | ||
| "name": "Badge Conference Event TEST", | ||
| "online_only": false, | ||
| "activity_producer_id": null, | ||
| "organization_id": "64ad9d19-1bd0-490f-b332-7c9f0ad1e024", | ||
| "partner_id": "64ac69a6-a344-4e05-bbc7-64670ad1e030", | ||
| "postal_code": "19107", | ||
| "privacy_type": "0", | ||
| "region": null, | ||
| "slug": "badge-conference-event-test", | ||
| "start": "2029-03-01 23:30:00", | ||
| "start_utc": "2029-03-02 04:30:00", | ||
| "state": "PA", | ||
| "tickets_active": true, | ||
| "timezone": "America/New_York", | ||
| "website": "", | ||
| "event_topic_id": "589e8222-c4f8-4794-bde7-73d40a004b01", | ||
| "organization_name": "Voyeur DC", | ||
| "scheduled_publish_datetime_utc": null, | ||
| "event_topic": "Business", | ||
| "category": "Business", | ||
| "event_url": "https://grindr.ticketsauce.com/e/badge-conference-event-test", | ||
| "tickets_url": "https://grindr.ticketsauce.com/e/badge-conference-event-test/tickets", | ||
| "display_times": true, | ||
| "order_count": 4, | ||
| "partner_name": "Grindr Demo" | ||
| }, | ||
| "Logo": { | ||
| "url": "https://res.cloudinary.com/eventservice/image/upload/q_auto,f_auto/v1751769059/saas/logos/image_1751769042730_r9qr7df7d.webp", | ||
| "created": "2025-06-26 03:04:39" | ||
| }, | ||
| "Masthead": { | ||
| "url": null, | ||
| "created": null | ||
| } | ||
| }, | ||
| { | ||
| "Event": { | ||
| "active": true, | ||
| "address": "", | ||
| "address2": "", | ||
| "city": "San Jose", | ||
| "country": "United States", | ||
| "created": "2025-07-23 01:23:07", | ||
| "custom_id": null, | ||
| "show_start": true, | ||
| "show_end": false, | ||
| "end": "2026-05-03 23:00:00", | ||
| "end_utc": "2026-05-04 06:00:00", | ||
| "featured": false, | ||
| "id": "6880397b-3624-4dc9-8e62-00140a1e60f5", | ||
| "location": "San Jose", | ||
| "latitude": null, | ||
| "longitude": null, | ||
| "map_zoom": "13", | ||
| "modified": "2025-07-23 07:10:35", | ||
| "name": "Festival Wristband Event", | ||
| "online_only": false, | ||
| "activity_producer_id": null, | ||
| "organization_id": "64ad9d19-1bd0-490f-b332-7c9f0ad1e024", | ||
| "partner_id": "64ac69a6-a344-4e05-bbc7-64670ad1e030", | ||
| "postal_code": "", | ||
| "privacy_type": "0", | ||
| "region": null, | ||
| "slug": "festival-wristband-event", | ||
| "start": "2026-05-01 18:00:00", | ||
| "start_utc": "2026-05-02 01:00:00", | ||
| "state": "CA", | ||
| "tickets_active": true, | ||
| "timezone": "America/Los_Angeles", | ||
| "website": "", | ||
| "event_topic_id": "c2fc3d42-c85f-4ecf-a0df-19d0a8659353", | ||
| "organization_name": "Voyeur DC", | ||
| "scheduled_publish_datetime_utc": null, | ||
| "event_topic": "Festival", | ||
| "category": "Festival", | ||
| "event_url": "https://grindr.ticketsauce.com/e/festival-wristband-event", | ||
| "tickets_url": "https://grindr.ticketsauce.com/e/festival-wristband-event/tickets", | ||
| "display_times": true, | ||
| "order_count": 1, | ||
| "partner_name": "Grindr Demo" | ||
| }, | ||
| "Logo": { | ||
| "url": "https://res.cloudinary.com/eventservice/image/upload/q_auto,f_auto/v1753233876/saas/logos/image_1753233797906_s3hyoqr1m.webp", | ||
| "created": "2025-07-23 01:24:38" | ||
| }, | ||
| "Masthead": { | ||
| "url": null, | ||
| "created": null | ||
| } | ||
| } | ||
| ``` | ||
|  | ||
| get-orders | ||
| Prompt | ||
| Get a list of orders from the specified event. | ||
|  | ||
| -When you come up for the description for this component following format: <component description>. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#orders) | ||
| -for the prop related to event_id (path parameter) use async options so users can select an event. | ||
| -as referece examples for async options you can use those found in apps zendesk, guru, etsy and recently you helped me come up with async options for prop imageId in generate-motion.mjs of leonardo ai app. | ||
| -when returning the context object, if there are no more options to return, simply return an empty object {} | ||
| -here is the response example for "list events" endpoint for you to come up with logic on how to implement async options for the prop related to event_id | ||
| ``` | ||
| [ | ||
| { | ||
| "Event": { | ||
| "active": true, | ||
| "address": "1221 Saint James Street", | ||
| "address2": "", | ||
| "city": "Philadelphia", | ||
| "country": "United States", | ||
| "created": "2025-06-26 02:40:59", | ||
| "custom_id": null, | ||
| "show_start": true, | ||
| "show_end": false, | ||
| "end": "2029-03-01 23:45:00", | ||
| "end_utc": "2029-03-02 04:45:00", | ||
| "featured": false, | ||
| "id": "685cb33b-0dc8-462d-ae5b-00410a1e60d3", | ||
| "location": "Voyeur Nightclub", | ||
| "latitude": "39.948357", | ||
| "longitude": "-75.161697", | ||
| "map_zoom": "13", | ||
| "modified": "2025-09-16 22:08:06", | ||
| "name": "Badge Conference Event TEST", | ||
| "online_only": false, | ||
| "activity_producer_id": null, | ||
| "organization_id": "64ad9d19-1bd0-490f-b332-7c9f0ad1e024", | ||
| "partner_id": "64ac69a6-a344-4e05-bbc7-64670ad1e030", | ||
| "postal_code": "19107", | ||
| "privacy_type": "0", | ||
| "region": null, | ||
| "slug": "badge-conference-event-test", | ||
| "start": "2029-03-01 23:30:00", | ||
| "start_utc": "2029-03-02 04:30:00", | ||
| "state": "PA", | ||
| "tickets_active": true, | ||
| "timezone": "America/New_York", | ||
| "website": "", | ||
| "event_topic_id": "589e8222-c4f8-4794-bde7-73d40a004b01", | ||
| "organization_name": "Voyeur DC", | ||
| "scheduled_publish_datetime_utc": null, | ||
| "event_topic": "Business", | ||
| "category": "Business", | ||
| "event_url": "https://grindr.ticketsauce.com/e/badge-conference-event-test", | ||
| "tickets_url": "https://grindr.ticketsauce.com/e/badge-conference-event-test/tickets", | ||
| "display_times": true, | ||
| "order_count": 4, | ||
| "partner_name": "Grindr Demo" | ||
| }, | ||
| "Logo": { | ||
| "url": "https://res.cloudinary.com/eventservice/image/upload/q_auto,f_auto/v1751769059/saas/logos/image_1751769042730_r9qr7df7d.webp", | ||
| "created": "2025-06-26 03:04:39" | ||
| }, | ||
| "Masthead": { | ||
| "url": null, | ||
| "created": null | ||
| } | ||
| }, | ||
| { | ||
| "Event": { | ||
| "active": true, | ||
| "address": "", | ||
| "address2": "", | ||
| "city": "San Jose", | ||
| "country": "United States", | ||
| "created": "2025-07-23 01:23:07", | ||
| "custom_id": null, | ||
| "show_start": true, | ||
| "show_end": false, | ||
| "end": "2026-05-03 23:00:00", | ||
| "end_utc": "2026-05-04 06:00:00", | ||
| "featured": false, | ||
| "id": "6880397b-3624-4dc9-8e62-00140a1e60f5", | ||
| "location": "San Jose", | ||
| "latitude": null, | ||
| "longitude": null, | ||
| "map_zoom": "13", | ||
| "modified": "2025-07-23 07:10:35", | ||
| "name": "Festival Wristband Event", | ||
| "online_only": false, | ||
| "activity_producer_id": null, | ||
| "organization_id": "64ad9d19-1bd0-490f-b332-7c9f0ad1e024", | ||
| "partner_id": "64ac69a6-a344-4e05-bbc7-64670ad1e030", | ||
| "postal_code": "", | ||
| "privacy_type": "0", | ||
| "region": null, | ||
| "slug": "festival-wristband-event", | ||
| "start": "2026-05-01 18:00:00", | ||
| "start_utc": "2026-05-02 01:00:00", | ||
| "state": "CA", | ||
| "tickets_active": true, | ||
| "timezone": "America/Los_Angeles", | ||
| "website": "", | ||
| "event_topic_id": "c2fc3d42-c85f-4ecf-a0df-19d0a8659353", | ||
| "organization_name": "Voyeur DC", | ||
| "scheduled_publish_datetime_utc": null, | ||
| "event_topic": "Festival", | ||
| "category": "Festival", | ||
| "event_url": "https://grindr.ticketsauce.com/e/festival-wristband-event", | ||
| "tickets_url": "https://grindr.ticketsauce.com/e/festival-wristband-event/tickets", | ||
| "display_times": true, | ||
| "order_count": 1, | ||
| "partner_name": "Grindr Demo" | ||
| }, | ||
| "Logo": { | ||
| "url": "https://res.cloudinary.com/eventservice/image/upload/q_auto,f_auto/v1753233876/saas/logos/image_1753233797906_s3hyoqr1m.webp", | ||
| "created": "2025-07-23 01:24:38" | ||
| }, | ||
| "Masthead": { | ||
| "url": null, | ||
| "created": null | ||
| } | ||
| } | ||
| ``` | ||
| - Here are the parameters for the related get orders API endpoint, use as a basis for props: | ||
| per_page | ||
| integer optional | ||
| How many results to retrieve (per page). Max 500. | ||
| Default: | ||
| 100 | ||
|  | ||
| page | ||
| integer optional | ||
| Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60. | ||
| Default: | ||
| 1 | ||
|  | ||
| q | ||
| string optional | ||
| Exact email address or last name attached to an order. | ||
|  | ||
| return_questionnaires | ||
| boolean optional | ||
| Whether or not to return the question responses from questionnaires (will include attendee responses as well IF tickets are returned) | ||
| Default: | ||
| false | ||
|  | ||
| return_tickets | ||
| boolean optional | ||
| Whether or not to return the tickets for each order as well. | ||
| Default: | ||
| false | ||
|  | ||
| return_line_item_fees | ||
| boolean optional | ||
| Whether or not to return the itemized line item fees for each order (if they exist). | ||
| Default: | ||
| false | ||
|  | ||
| ordered_after | ||
| string optional | ||
| Only retrieve orders that were ordered AFTER the specified date/time (format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS). | ||
|  | ||
| ordered_before | ||
| string optional | ||
| Only retrieve orders that were ordered BEFORE the specified date/time (format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS). | ||
|  | ||
| ordered_phrase | ||
| string optional | ||
| A string representing the date to pull orders created ___. Possible values are: today, yesterday, tomorrow, this_week, this_weekend, next_week, next_weekend, this_month, next_month | ||
|  | ||
| modified_after | ||
| string optional | ||
| Only retrieve orders that were modified AFTER the specified date/time (format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS). | ||
|  | ||
| modified_before | ||
| string optional | ||
| Only retrieve orders that were modified BEFORE the specified date/time (format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS). | ||
|  | ||
| sort_by | ||
| string optional | ||
| Which field to sort by. By default (‘date’), this will sort orders by their ordered date. Or ‘name’ to order by last name. | ||
| Default: | ||
| 'date' | ||
|  | ||
| sort_dir | ||
| string optional | ||
| Which direction you’d like to sort - either ascending (‘asc’ - the default) or descending (‘desc’). | ||
| Default: | ||
| 'asc' | ||
| total_above | ||
|  | ||
| number optional | ||
| Return only orders who’s order total is greater than this value. | ||
| Default: | ||
| 0 | ||
|  | ||
| total_below | ||
| string optional | ||
| Return only orders who’s order total is lesss than this value. | ||
|  | ||
| promo_used_only | ||
| boolean optional | ||
| If set to true, this will return only orders who used a promo code. | ||
| Default: | ||
| false | ||
| ``` | ||
|  | ||
| get-order-details | ||
| Get details for the specified order. | ||
| -When you come up for the description for this component following format: <component description>. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#order-details) | ||
| - Here are the parameters for the related get order details API endpoint, use as a basis for props: | ||
| order_id | ||
| path parameter, string required | ||
| -add an additional prop related to event_id and use async options so users can select an event. | ||
| -as referece examples for async options you can use those found in apps zendesk, guru, etsy and recently you helped me come up with async options for prop imageId in generate-motion.mjs of leonardo ai app. | ||
| -when returning the context object, if there are no more options to return, simply return an empty object {} | ||
| -here is the response example for "list events" endpoint for you to come up with logic on how to implement async options for the prop related to id_or_slug | ||
| ``` | ||
| [ | ||
| { | ||
| "Event": { | ||
| "active": true, | ||
| "address": "1221 Saint James Street", | ||
| "address2": "", | ||
| "city": "Philadelphia", | ||
| "country": "United States", | ||
| "created": "2025-06-26 02:40:59", | ||
| "custom_id": null, | ||
| "show_start": true, | ||
| "show_end": false, | ||
| "end": "2029-03-01 23:45:00", | ||
| "end_utc": "2029-03-02 04:45:00", | ||
| "featured": false, | ||
| "id": "685cb33b-0dc8-462d-ae5b-00410a1e60d3", | ||
| "location": "Voyeur Nightclub", | ||
| "latitude": "39.948357", | ||
| "longitude": "-75.161697", | ||
| "map_zoom": "13", | ||
| "modified": "2025-09-16 22:08:06", | ||
| "name": "Badge Conference Event TEST", | ||
| "online_only": false, | ||
| "activity_producer_id": null, | ||
| "organization_id": "64ad9d19-1bd0-490f-b332-7c9f0ad1e024", | ||
| "partner_id": "64ac69a6-a344-4e05-bbc7-64670ad1e030", | ||
| "postal_code": "19107", | ||
| "privacy_type": "0", | ||
| "region": null, | ||
| "slug": "badge-conference-event-test", | ||
| "start": "2029-03-01 23:30:00", | ||
| "start_utc": "2029-03-02 04:30:00", | ||
| "state": "PA", | ||
| "tickets_active": true, | ||
| "timezone": "America/New_York", | ||
| "website": "", | ||
| "event_topic_id": "589e8222-c4f8-4794-bde7-73d40a004b01", | ||
| "organization_name": "Voyeur DC", | ||
| "scheduled_publish_datetime_utc": null, | ||
| "event_topic": "Business", | ||
| "category": "Business", | ||
| "event_url": "https://grindr.ticketsauce.com/e/badge-conference-event-test", | ||
| "tickets_url": "https://grindr.ticketsauce.com/e/badge-conference-event-test/tickets", | ||
| "display_times": true, | ||
| "order_count": 4, | ||
| "partner_name": "Grindr Demo" | ||
| }, | ||
| "Logo": { | ||
| "url": "https://res.cloudinary.com/eventservice/image/upload/q_auto,f_auto/v1751769059/saas/logos/image_1751769042730_r9qr7df7d.webp", | ||
| "created": "2025-06-26 03:04:39" | ||
| }, | ||
| "Masthead": { | ||
| "url": null, | ||
| "created": null | ||
| } | ||
| }, | ||
| { | ||
| "Event": { | ||
| "active": true, | ||
| "address": "", | ||
| "address2": "", | ||
| "city": "San Jose", | ||
| "country": "United States", | ||
| "created": "2025-07-23 01:23:07", | ||
| "custom_id": null, | ||
| "show_start": true, | ||
| "show_end": false, | ||
| "end": "2026-05-03 23:00:00", | ||
| "end_utc": "2026-05-04 06:00:00", | ||
| "featured": false, | ||
| "id": "6880397b-3624-4dc9-8e62-00140a1e60f5", | ||
| "location": "San Jose", | ||
| "latitude": null, | ||
| "longitude": null, | ||
| "map_zoom": "13", | ||
| "modified": "2025-07-23 07:10:35", | ||
| "name": "Festival Wristband Event", | ||
| "online_only": false, | ||
| "activity_producer_id": null, | ||
| "organization_id": "64ad9d19-1bd0-490f-b332-7c9f0ad1e024", | ||
| "partner_id": "64ac69a6-a344-4e05-bbc7-64670ad1e030", | ||
| "postal_code": "", | ||
| "privacy_type": "0", | ||
| "region": null, | ||
| "slug": "festival-wristband-event", | ||
| "start": "2026-05-01 18:00:00", | ||
| "start_utc": "2026-05-02 01:00:00", | ||
| "state": "CA", | ||
| "tickets_active": true, | ||
| "timezone": "America/Los_Angeles", | ||
| "website": "", | ||
| "event_topic_id": "c2fc3d42-c85f-4ecf-a0df-19d0a8659353", | ||
| "organization_name": "Voyeur DC", | ||
| "scheduled_publish_datetime_utc": null, | ||
| "event_topic": "Festival", | ||
| "category": "Festival", | ||
| "event_url": "https://grindr.ticketsauce.com/e/festival-wristband-event", | ||
| "tickets_url": "https://grindr.ticketsauce.com/e/festival-wristband-event/tickets", | ||
| "display_times": true, | ||
| "order_count": 1, | ||
| "partner_name": "Grindr Demo" | ||
| }, | ||
| "Logo": { | ||
| "url": "https://res.cloudinary.com/eventservice/image/upload/q_auto,f_auto/v1753233876/saas/logos/image_1753233797906_s3hyoqr1m.webp", | ||
| "created": "2025-07-23 01:24:38" | ||
| }, | ||
| "Masthead": { | ||
| "url": null, | ||
| "created": null | ||
| } | ||
| } | ||
| ``` | ||
| - with the user selection of event_id you will dynamically populate async options for the order_id prop. You can reference the Google Sheets app, delete rows action, where Worksheet ID prop is dynamically populated based off the Spreadsheet ID selecfed by the user. | ||
| -here is the response example for "get orders" endpoint for you to come up with logic on how to implement async options for the prop related to order_id | ||
| ``` | ||
| [{"Order":{"id":"68803b8b-d290-4476-bed7-00120a1e6305","status":"1","last_name":"Lawrence","first_name":"Reid","dob":null,"email":"[email protected]","phone":"(999) 888-5555","title":null,"company":null,"address":null,"address2":null,"city":"Philly","state":"PA","postal_code":null,"country":"US","opted_in":false,"opted_in_sms":false,"subtotal":"0.00","total_paid":"0.00","refund_amount":"0.00","taxes":"0.00","contributions":"0.00","service_charges":"0.00","cc_fees":"0.00","admin_charges":"0.00","custom_line_item_fees":"0.00","policy_total":"0.00","policy_refunded":"0.00","ticket_count":"4","promo_code_amount":"0.00","promo_code":null,"promo_code_id":null,"purchase_location":"online","paid_date":"2025-07-22 18:31:55","paid_date_utc":"2025-07-23 01:31:55","affiliate_code":null,"event_id":"6880397b-3624-4dc9-8e62-00140a1e60f5","modified":"2025-07-23 01:31:55","delivery_method":"email","affiliate_code_id":null,"affiliate_code_name":null,"promoter_id":null,"promoter_name":null}}] | ||
| ``` | ||
|  | ||
| get-ticket-checkin-ids | ||
| Prompt | ||
| Get a list of ticket check-in IDs from the specified event. | ||
| -When you come up for the description for this component following format: <component description>. [See documentation](https://speca.io/ticketsauce/ticketsauce-public-api?key=204000d6bda66da78315e721920f43aa#ticket-checkin-ids) | ||
| - Here are the parameters for the related API endpoint, use as a basis for props: | ||
| ``` | ||
| Path parameters | ||
| event_id | ||
| string required | ||
| ID of event | ||
|  | ||
| query string parameters | ||
| per_page | ||
| integer optional | ||
| How many results to retrieve (per page). Max 5000. | ||
|  | ||
| page | ||
| integer optional | ||
| Which page to return. For example, if per_page is 20, and page is 3, the results would show 41-60. | ||
| Default: | ||
| 1 | ||
| ``` | ||
| -for the prop related to id_or_slug use async options so users can select an event. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Specification content is thorough but lacks implementation.
While the action specifications (get-events, get-event-details, get-orders, get-order-details, get-ticket-checkin-ids) are well-documented with parameter details, response examples, and async options guidance, the file contains no executable component code. The specifications reference implementation patterns (lines 8: "wrap API calls with _makeRequest", line 157: "use async options for props") but do not provide the actual implementation.
Should the implementation code be:
- In separate .mjsor.jsfiles (following Pipedream component conventions), or
- Included in this .mdcfile in a code block marked for extraction?
Please provide the actual component implementations matching these specifications.
---
🏁 Script executed:
```shell
#!/bin/bash
# Find the ticketsauce components file
find . -name "*ticketsauce*" -type f 2>/dev/null | head -20
Length of output: 96
🏁 Script executed:
#!/bin/bash
# List the structure of the ticketsauce directory
find ./components/ticketsauce -type f -name "*.mdc" -o -name "*.mjs" -o -name "*.js" 2>/dev/null | sortLength of output: 96
🏁 Script executed:
#!/bin/bash
# Check if the specific file exists and show its structure
if [ -f "components/ticketsauce/ticketsauce_components.mdc" ]; then
  wc -l components/ticketsauce/ticketsauce_components.mdc
  head -100 components/ticketsauce/ticketsauce_components.mdc
fiLength of output: 3553
🏁 Script executed:
#!/bin/bash
# Check for any implementation files
find ./components/ticketsauce -type f \( -name "*.mjs" -o -name "*.js" \) 2>/dev/nullLength of output: 44
---
🏁 Script executed:
```shell
#!/bin/bash
# View the full .mdc file to check if it contains implementation code
cat components/ticketsauce/ticketsauce_components.mdc
Length of output: 29875
🏁 Script executed:
#!/bin/bash
# Check ticketsauce.app.mjs to understand app structure
head -50 components/ticketsauce/ticketsauce.app.mjsLength of output: 215
🏁 Script executed:
#!/bin/bash
# Compare with zendesk component structure
find ./components/zendesk -type f \( -name "*.mjs" -o -name "*.mdc" \) 2>/dev/null | head -10Length of output: 633
🏁 Script executed:
#!/bin/bash
# Compare with leonardo_ai component structure  
find ./components/leonardo_ai -type f \( -name "*.mjs" -o -name "*.mdc" \) 2>/dev/null | head -10Length of output: 371
Missing component action implementations across five TicketSauce actions.
The file contains comprehensive specifications but no executable code. Compared to standard Pipedream structure (zendesk, leonardo_ai), each action requires a separate .mjs file in the components/ticketsauce/actions/<action-name>/ directory:
- get-events/get-events.mjs
- get-event-details/get-event-details.mjs
- get-orders/get-orders.mjs
- get-order-details/get-order-details.mjs
- get-ticket-checkin-ids/get-ticket-checkin-ids.mjs
The .mdc file (with alwaysApply: true frontmatter) is a specification document that references implementation patterns but does not provide the actual component code. Create the five action files following the provided parameter schemas, async options logic, and API patterns documented in the spec.
🤖 Prompt for AI Agents
In components/ticketsauce/ticketsauce_components.mdc around lines 54-632 the
review notes that five TicketSauce actions are only specified but not
implemented: get-events, get-event-details, get-orders, get-order-details, and
get-ticket-checkin-ids; implement each as a separate .mjs under
components/ticketsauce/actions/<action-name>/ with proper Pipedream action
structure, request logic using the documented endpoints and params, async
options for event selection (id_or_slug/event_id) that call the list-events
endpoint and map Event.name + Event.id (or slug) into {label,value} pairs,
ensure async options return an empty object {} when no more results, and for
get-order-details make event_id an async-prop and dynamically populate order_id
options by calling the get-orders endpoint for the selected event; follow
patterns from existing apps (zendesk, guru, etsy, leonardo_ai) for auth and
pagination, validate required path params, and export default action handlers
that return the API response.
WHY
Resolves #17749, components for the 302.AI app
Summary by CodeRabbit
Release Notes
New Features
Chores