Conversation
Fix 3 pre-existing TypeScript errors in challenge-context-workflow.ts:313 and skill-extraction-workflow.ts:102,146 by adding the required 'observe' property (noopObserve from @mastra/core/tools) to tool.execute?.() calls. ToolExecutionContext requires observe as a non-optional field. Install new dependencies for RAG pipeline: - Production: @mastra/rag@^2.5.0 (2.6.0), turndown, js-tiktoken, csv-parse - Dev: @types/turndown, tsx Verified @mastra/rag 2.6.0: MDocument.chunk() returns chunks with 'text' field (not 'content'), confirming architecture assumptions. Green baseline confirmed: tsc --noEmit, pnpm lint, pnpm test, pnpm run build all pass with exit code 0. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Create src/config/rag.config.ts with lazy getRagConfig() that never throws at module load (D5). Provider/model dimension map: TC-Ollama/nomic-embed-text → 768/2048, AWSBedrock/amazon.titan-embed-text-v2:0 → 1024/8192. All RAG env vars overridable with defaults. VECTOR_INDEX_NAME validated as SQL identifier. type/track as free-form strings (D12). Reuses MASTRA_DB_CONNECTION and MASTRA_DB_SCHEMA. Create src/utils/providers/embedding-factory.ts with createEmbeddingModel() switch mirroring createModel: TC-Ollama → ollama.embedding(), AWSBedrock → createBedrockProvider().embedding(). Unknown provider throws actionable error. Logs via tcAILogger. Re-exported from src/utils/index.ts. 33 unit tests covering all config and factory behaviors (VAL-FOUND-021 through VAL-FOUND-033). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Create src/mastra/vector/challenge-vector-store.ts with: - getChallengeVectorStore(): lazy PgVector singleton (created on first call, not at module load) constructed with id, connectionString, and schemaName from MASTRA_DB_CONNECTION/MASTRA_DB_SCHEMA - ensureChallengeIndex(): idempotently creates HNSW index with cosine metric and metadataIndexes for challengeId, projectId, track - D7 dimension guard: compares describeIndex().dimension against configured model dimension, throws actionable error on mismatch - No disconnect() on request paths (singleton persists for process lifetime) - 29 unit tests with mocked PgVector covering all 6 validation assertions Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…unit tests
Ports the prototype's pure library code into src/mastra/rag/ (ADR 0001 Phase 3):
- content.ts: normalizeLineEndings, BOM-aware trim, stripFrontmatter,
htmlToMarkdown (Turndown, atx headings + fenced code), parseSkills, generic
enrichChunksWithChallengeName, processDescription (normalize -> trim ->
htmlToMarkdown -> stripFrontmatter, in that order)
- chunking.ts: chunkChallengeDescription as a pure two-pass function
(markdown header pass with stripHeaders: false, then size-based pass).
Code blocks and tables stay atomic while under floor(contextWindow * 0.97)
tokens; oversized ones are force-split at safeCharLimit = contextWindow * 3
(6144), NOT maxSize (512). Returns { chunks, forceSplits }.
- ingestion-utils.ts: withRetry with LINEAR backoff (delay * attempt), sleep,
REQUIRED_COLUMNS, validateColumns, validateRecord (id/name/description only),
generateDeterministicId (SHA-256 rendered UUID-shaped)
- types.ts: ChallengeRecord, ChunkingOptions derived from RagConfig,
ChallengeChunk, ForceSplitRecord, ChunkMetadata (text field, not content;
projectId as string; new groups/ingestedAt fields), IngestionReport,
IngestOptions
89 new unit tests colocated as src/mastra/rag/*.test.ts.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Additively adds projectId: z.number().optional() and groups: z.array(z.string()).optional() to the fetchChallengeTool output schema and mapping function. projectId from the Challenge API is Int? (nullable); null/absent values become undefined via ?? undefined. The challenge-context-workflow uses z.any() for the challenge object so it is unaffected. The app-version: 2.0.0 header is preserved unchanged. 15 unit tests verify: - projectId present when API returns a number - projectId omitted when API returns null or is absent - groups present when API returns an array - groups omitted when API does not include them - both fields passed through in mapping - output schema includes and preserves both fields - existing fields, headers, error handling unchanged Fulfills VAL-INGEST-053 through VAL-INGEST-058. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…ilters
Wraps the Topcoder v6 Challenges API search endpoint with M2M auth.
Supports filters: projectId/projectIds, status, approvalStatus, types/tracks,
tags, groups, updatedDateStart/End, ids, page, perPage, sortBy, sortOrder.
Always sets isLightweight=false (lightweight omits description), includes
app-version: 2.0.0 header, 15s timeout via AbortSignal.timeout(15_000).
Handles bare-array API response, wraps into { challenges, total, page, perPage }.
Discards privateDescription from return value. Throws on upstream non-2xx.
26 unit tests with mocked HTTP covering all 8 validation assertions.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…tests
Implements src/mastra/workflows/challenge/challenge-ingestion-workflow.ts
(id: challenge-ingestion) registered in src/mastra/index.ts:
- Step resolve-challenge: fetch by challengeId via fetchChallengeTool or
validate inline record with validateRecord; exactly-one-source enforced
- Step chunk-and-embed: processDescription → chunkChallengeDescription →
enrichChunksWithChallengeName → embedMany with withRetry (linear backoff);
only public description embedded, never privateDescription
- Step upsert-vectors: ensureChallengeIndex() → upsert with deleteFilter
{ challengeId } for atomic per-challenge replacement; skipped on dryRun
- Metadata: all 11 fields (challengeId, name, type, track, skills[], groups[],
projectId string|null, chunkIndex 1-based, totalChunks, text with
# Challenge: header, ingestedAt ISO-8601)
- Logging via tcAILogger with [challenge-ingestion:<step>] prefixes
- Config lazy via getRagConfig() inside step execute (D5)
- No console interception (D6), no projects-api call (D10)
- 41 unit tests covering happy paths, dryRun, error handling, metadata,
idempotent re-ingestion, embedding vs database failure, dimension guard
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…-out Adds src/mastra/workflows/challenge/challenge-bulk-ingestion-workflow.ts (id: challenge-bulk-ingestion), registered in src/mastra/index.ts: - collect-challenges paginates searchChallengesTool (1-based page/perPage, stops on an empty or short page, bounded by a maxPages guard) and emits one task per matched challenge; the v6 API validates status as a scalar enum, so the default ACTIVE + COMPLETED filter runs one paginated pass per status with results de-duplicated by challenge id. - ingest-one-challenge runs challenge-ingestion imperatively (getWorkflowById -> createRun -> run.start) and converts every failure path into a failed item result, so one bad challenge cannot kill the fan-out queue or abort the run. - .foreach fan-out with a concurrency resolver reading the workflow input (default 3, clamped to 1..10). - aggregate-reports reduces the per-challenge results into processed / succeeded / failed / skipped / totalChunks / forceSplits while retaining every per-challenge entry; zero matches yields zero-valued totals. Also fixes searchChallengesTool array-filter serialization: the v6 endpoint rejects both comma-joined and bare single values for types/tracks/tags/groups with `"criteria.<field>" must be an array` (HTTP 400), so those filters are now sent as bracketed array params (key[]=value). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Records the decision, hazards, phased plan, data model, and security notes for porting tc-challenges-vector-rag's ingestion and retrieval pipeline into tc-ai-api. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkcggGkcnz73GXUDR7mgrE
…tic workflow Phase 5 of ADR 0001. challengeVectorQueryTool composes the $and metadata filter (skills/type/track/groups/projectId) and is shared by two retrieval paths so they cannot diverge (D8): challenge-search-agent for synthesised NL answers, and the challenge-search workflow for raw ranked results with no LLM call, grouped by chunk/challenge/project. The relevance threshold is post-filtered in app code to preserve the HNSW ANN fast path, and query is optional so a filter-only call becomes a metadata-only lookup. Also adds fetchProjectTool (D10) — optional retrieval-time enrichment that resolves a projectId from a hit to project detail, never used during ingestion. Registers challengeSearchAgent and challengeSearchWorkflow in the Mastra instance. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkcggGkcnz73GXUDR7mgrE
Phase 6 of ADR 0001 — secondary bulk-ingestion path (D11), for
offline/air-gapped environments and CSV exports that predate the
Challenge Search API.
- ingestion-logger.ts: hierarchical file logger ported from the source
prototype, minus interceptConsole (D6) — per-run logs/ingestion-<ts>/
{output.log,error.log,report.json}.
- ingest-challenges.ts: streams CSV rows and invokes the challenge-ingestion
workflow per record via mastra.getWorkflowById().createRun().start(), so
CLI and API share one implementation. --clear-all drops the vector index
via deleteIndex() (the actual @mastra/pg 1.19 API for "delete everything" —
deleteVectors() explicitly rejects an empty filter and points here).
- sync-challenges.ts: thin wrapper around challenge-bulk-ingestion for
incremental sync / project-scoped backfill from the CLI.
- package.json ingest/sync scripts, logs/ in .gitignore, a small CSV
fixture for tests.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkcggGkcnz73GXUDR7mgrE
Phase 7 of ADR 0001 — configuration surface and documentation, adapted from the source prototype's README. Adds a Challenges Vector RAG section (overview, ingestion, retrieval, chunking strategy, metadata schema, embedding-model/dimension table, database bootstrap) plus new rows under Environment Variables and API Surface. .env.sh and .env (both gitignored, untracked) were also given the same commented reference block locally. Dockerfile/.circleci need no change — the image build already runs lint, test, and build against this branch, and `pnpm run build` bundles turndown and @mastra/rag into .mastra/output cleanly with no bundler config change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkcggGkcnz73GXUDR7mgrE
Challenges rag -> dev
The Agents and Tools sections only covered skillsMatchingAgent and the two skills tools, predating challengeParserAgent, jdRewriterAgent, challengeSearchAgent, and the four Challenge/Project tools. Adds per-agent/tool detail sections plus summary tables, and corrects two stale facts: skillsMatchingAgent now defaults to Bedrock (not Ollama mistral), and its scorers are gated on LOCAL_DEV=true. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkcggGkcnz73GXUDR7mgrE
Challenges rag -> dev
add auth logs -> dev
dump only resourceId on auth resolve -> dev
fix tests for auth breaking the build -> dev
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://topcoder.atlassian.net/browse/PM-5972