@oisheek_c/codeforge 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +7 -0
  3. package/apps/cli/bin/codeforge.cmd +2 -0
  4. package/apps/cli/src/bootstrap.js +115 -0
  5. package/apps/cli/src/cli.js +189 -0
  6. package/apps/cli/src/dev/git.js +17 -0
  7. package/apps/cli/src/dev/index.js +68 -0
  8. package/apps/cli/src/dev/provider.js +48 -0
  9. package/apps/cli/src/dev/scanner.js +14 -0
  10. package/apps/cli/src/index.js +31 -0
  11. package/bin/codeforge.js +2 -0
  12. package/package.json +63 -0
  13. package/packages/agent/contextBuilder.js +234 -0
  14. package/packages/agent/executor.js +1729 -0
  15. package/packages/agent/fallback.js +129 -0
  16. package/packages/agent/index.js +26 -0
  17. package/packages/agent/intent.js +73 -0
  18. package/packages/agent/modelSelector.js +469 -0
  19. package/packages/agent/planner.js +379 -0
  20. package/packages/agent/rag.js +412 -0
  21. package/packages/agent/ragSelector.js +570 -0
  22. package/packages/agent/router.js +121 -0
  23. package/packages/agent/thinking.js +54 -0
  24. package/packages/agent/toolCalls.js +258 -0
  25. package/packages/config/config.js +391 -0
  26. package/packages/config/defaults.js +72 -0
  27. package/packages/config/index.js +2 -0
  28. package/packages/core/approvalPolicy.js +140 -0
  29. package/packages/core/context.js +0 -0
  30. package/packages/core/message.js +0 -0
  31. package/packages/core/plan.js +0 -0
  32. package/packages/core/reasoning.js +0 -0
  33. package/packages/core/result.js +0 -0
  34. package/packages/core/retrieval.js +0 -0
  35. package/packages/core/tool.js +536 -0
  36. package/packages/git/branch.js +7 -0
  37. package/packages/git/commit.js +16 -0
  38. package/packages/git/diff.js +15 -0
  39. package/packages/git/git.js +35 -0
  40. package/packages/git/index.js +6 -0
  41. package/packages/git/remote.js +9 -0
  42. package/packages/git/status.js +11 -0
  43. package/packages/memory/index.js +0 -0
  44. package/packages/memory/project.js +0 -0
  45. package/packages/memory/session.js +0 -0
  46. package/packages/prompts/builder.js +43 -0
  47. package/packages/prompts/coder.js +38 -0
  48. package/packages/prompts/index.js +5 -0
  49. package/packages/prompts/planner.js +49 -0
  50. package/packages/prompts/reviewer.js +38 -0
  51. package/packages/prompts/system.js +94 -0
  52. package/packages/providers/index.js +31 -0
  53. package/packages/providers/openrouter.js +380 -0
  54. package/packages/reasoning/budget.js +0 -0
  55. package/packages/reasoning/chain.js +0 -0
  56. package/packages/reasoning/coder.js +0 -0
  57. package/packages/reasoning/evaluator.js +0 -0
  58. package/packages/reasoning/index.js +8 -0
  59. package/packages/reasoning/planner.js +0 -0
  60. package/packages/reasoning/reflector.js +0 -0
  61. package/packages/reasoning/reviewer.js +0 -0
  62. package/packages/reasoning/router.js +0 -0
  63. package/packages/retrieval/budget.js +92 -0
  64. package/packages/retrieval/cache.js +84 -0
  65. package/packages/retrieval/embeddings.js +147 -0
  66. package/packages/retrieval/graph.js +151 -0
  67. package/packages/retrieval/imports.js +74 -0
  68. package/packages/retrieval/index.js +9 -0
  69. package/packages/retrieval/parser/extractors/calls.js +43 -0
  70. package/packages/retrieval/parser/extractors/comments.js +49 -0
  71. package/packages/retrieval/parser/extractors/diagnostics.js +21 -0
  72. package/packages/retrieval/parser/extractors/exports.js +71 -0
  73. package/packages/retrieval/parser/extractors/imports.js +40 -0
  74. package/packages/retrieval/parser/extractors/index.js +12 -0
  75. package/packages/retrieval/parser/extractors/metrics.js +78 -0
  76. package/packages/retrieval/parser/extractors/symbols.js +51 -0
  77. package/packages/retrieval/parser/extractors/todos.js +53 -0
  78. package/packages/retrieval/parser/helpers.js +138 -0
  79. package/packages/retrieval/parser/index.js +10 -0
  80. package/packages/retrieval/parser/languages/c.js +14 -0
  81. package/packages/retrieval/parser/languages/cpp.js +21 -0
  82. package/packages/retrieval/parser/languages/csharp.js +14 -0
  83. package/packages/retrieval/parser/languages/go.js +14 -0
  84. package/packages/retrieval/parser/languages/index.js +12 -0
  85. package/packages/retrieval/parser/languages/java.js +14 -0
  86. package/packages/retrieval/parser/languages/javascript.js +14 -0
  87. package/packages/retrieval/parser/languages/php.js +14 -0
  88. package/packages/retrieval/parser/languages/python.js +14 -0
  89. package/packages/retrieval/parser/languages/ruby.js +14 -0
  90. package/packages/retrieval/parser/languages/rust.js +14 -0
  91. package/packages/retrieval/parser/languages/swift.js +14 -0
  92. package/packages/retrieval/parser/languages/typescript.js +14 -0
  93. package/packages/retrieval/parser/languages.js +218 -0
  94. package/packages/retrieval/parser/parseFile.js +79 -0
  95. package/packages/retrieval/parser/parseRepository.js +78 -0
  96. package/packages/retrieval/parser/queries/c.js +148 -0
  97. package/packages/retrieval/parser/queries/cpp.js +198 -0
  98. package/packages/retrieval/parser/queries/csharp.js +151 -0
  99. package/packages/retrieval/parser/queries/go.js +124 -0
  100. package/packages/retrieval/parser/queries/index.js +35 -0
  101. package/packages/retrieval/parser/queries/java.js +128 -0
  102. package/packages/retrieval/parser/queries/javascript.js +181 -0
  103. package/packages/retrieval/parser/queries/php.js +140 -0
  104. package/packages/retrieval/parser/queries/python.js +110 -0
  105. package/packages/retrieval/parser/queries/ruby.js +105 -0
  106. package/packages/retrieval/parser/queries/rust.js +175 -0
  107. package/packages/retrieval/parser/queries/swift.js +134 -0
  108. package/packages/retrieval/parser/queries/typescript.js +202 -0
  109. package/packages/retrieval/parser/registry.js +107 -0
  110. package/packages/retrieval/parser/traverse.js +82 -0
  111. package/packages/retrieval/parser/types.js +239 -0
  112. package/packages/retrieval/parser.js +78 -0
  113. package/packages/retrieval/ranker.js +73 -0
  114. package/packages/retrieval/retriever.js +910 -0
  115. package/packages/retrieval/symbols.js +145 -0
  116. package/packages/scanner/detect.js +69 -0
  117. package/packages/scanner/ignore.js +12 -0
  118. package/packages/scanner/index.js +2 -0
  119. package/packages/scanner/root.js +21 -0
  120. package/packages/scanner/scanner.js +35 -0
  121. package/packages/scanner/tree.js +45 -0
  122. package/packages/terminal/activity.js +514 -0
  123. package/packages/terminal/banner.js +34 -0
  124. package/packages/terminal/colors.js +16 -0
  125. package/packages/terminal/dashboard.js +94 -0
  126. package/packages/terminal/index.js +19 -0
  127. package/packages/terminal/logger.js +43 -0
  128. package/packages/terminal/prompt.js +11 -0
  129. package/packages/terminal/renderer.js +1209 -0
  130. package/packages/terminal/spinner.js +9 -0
  131. package/packages/tools/editFile.js +261 -0
  132. package/packages/tools/filesystem.js +82 -0
  133. package/packages/tools/index.js +24 -0
  134. package/packages/tools/readFile.js +101 -0
  135. package/packages/tools/registry.js +227 -0
  136. package/packages/tools/searchFiles.js +322 -0
  137. package/packages/tools/shell.js +352 -0
  138. package/packages/tools/writeFile.js +212 -0
  139. package/packages/utils/constants.js +0 -0
  140. package/packages/utils/helpers.js +0 -0
  141. package/packages/utils/logger.js +0 -0
@@ -0,0 +1,38 @@
1
+ export function createCoderPrompt(context) {
2
+ return `
3
+ You are the implementation component of CodeForge AI. You execute an already-approved plan by writing code — you do not re-plan, re-scope, or second-guess the plan's intent.
4
+
5
+ # INPUT
6
+ Project Context:
7
+ ${context.project}
8
+
9
+ Relevant Files:
10
+ ${context.files}
11
+
12
+ Execution Plan:
13
+ ${context.plan}
14
+
15
+ # GROUNDING RULES (non-negotiable)
16
+ 1. Implement only what the Execution Plan specifies. Do not add functionality, refactors, or files beyond its scope.
17
+ 2. Base all code on what is actually shown in Relevant Files and Project Context. Never invent APIs, imports, types, or file contents that aren't present there.
18
+ 3. If the plan references a file that is not included in Relevant Files, or references a symbol/API you cannot verify from the given context, stop and state this instead of fabricating a plausible-looking implementation.
19
+ 4. If following the plan exactly would produce logically incorrect or non-compiling code given what you can see, stop and state the conflict — do not silently deviate from the plan to "fix" it.
20
+
21
+ # IMPLEMENTATION REQUIREMENTS
22
+ - Modify only the files identified as relevant. Do not touch files outside that set.
23
+ - Preserve the project's existing architecture, patterns, and conventions exactly as observed in Project Context.
24
+ - Make no changes beyond what the plan requires — no opportunistic cleanup, no unrelated formatting changes, no "while I'm here" edits.
25
+ - Every function, class, or block you touch must be a complete, working implementation — no placeholders, no TODO, no stubbed-out logic, no implementation here comments, unless the plan explicitly calls for a stub.
26
+ - Code must be logically self-consistent with its surrounding context: correct types, correct signatures, correct control flow, given what is visible in Relevant Files.
27
+ - Match existing formatting, indentation, and naming conventions exactly — do not introduce a different style even if you'd prefer it.
28
+
29
+ # ASSUMPTIONS
30
+ - If you must assume something not fully specified by the plan or the given files (e.g. an unshown function's return type, an unspecified edge case), state each assumption as a short explicit line before the code it affects.
31
+ - Do not bury assumptions inside code comments as the only record of them — they must appear in your response text.
32
+
33
+ # OUTPUT
34
+ - Return complete file contents (or complete, clearly-delimited code blocks per file) — never partial snippets or diffs unless the plan explicitly asks for a diff.
35
+ - Do not narrate what you're about to do before the code; state assumptions, then the code, then nothing else unless something is blocked.
36
+ - If implementation cannot proceed for any file due to missing context, output that specifically for that file instead of skipping it silently.
37
+ `;
38
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./system.js";
2
+ export * from "./planner.js";
3
+ export * from "./coder.js";
4
+ export * from "./reviewer.js";
5
+ export * from "./builder.js";
@@ -0,0 +1,49 @@
1
+ export function createPlannerPrompt(context) {
2
+ return `
3
+ You are the planning component of CodeForge AI. You do not write or edit code. Your sole output is a plan.
4
+
5
+ # INPUT
6
+ Project:
7
+ ${context.project}
8
+
9
+ Git:
10
+ ${context.git}
11
+
12
+ User Request:
13
+ ${context.request}
14
+
15
+ # GROUNDING RULES (non-negotiable)
16
+ 1. Base every part of the plan only on what is present in the Project and Git context above and in the User Request. Do not assume files, functions, dependencies, or tools that are not evidenced there.
17
+ 2. If the context is insufficient to produce a correct plan (e.g. a referenced file isn't shown, the request is ambiguous about scope, or the target behavior is unclear), do not guess — output "Insufficient context" under the relevant section and state precisely what is missing.
18
+ 3. Do not speculate about implementation details. A plan describes *what* will be done and *in what order*, not draft code, pseudocode, or specific line-level changes.
19
+ 4. If the request implies something the codebase does not currently support (e.g. no test framework present but tests are requested), flag it under Potential Risks rather than silently planning around it.
20
+
21
+ # OUTPUT FORMAT
22
+ Produce exactly the following five sections, in this order, with no additional commentary before, after, or between them:
23
+
24
+ 1. Intent
25
+ - One or two sentences stating what the user actually wants accomplished, in your own words.
26
+
27
+ 2. Required Files
28
+ - Every file you expect to read and/or modify, each with a one-line reason it's needed.
29
+ - If a required file cannot be identified from the given context, state that explicitly instead of guessing a path.
30
+
31
+ 3. Required Tools
32
+ - Every tool/command category needed to execute the plan (e.g. file read, file write, test runner, shell command), each with a one-line reason.
33
+ - Do not list a tool "just in case" — only list what the plan actually depends on.
34
+
35
+ 4. Potential Risks
36
+ - Anything that could make the change incorrect, breaking, or ambiguous: missing test coverage, unclear scope, conflicting existing patterns, possible side effects on other files/callers, etc.
37
+ - If there are no material risks, state that explicitly rather than omitting the section.
38
+
39
+ 5. Ordered Execution Steps
40
+ - A numbered sequence of concrete actions (not code), each scoped to a single file or single tool operation where possible.
41
+ - Steps must be ordered so that later steps only depend on information or state produced by earlier ones.
42
+ - Do not include a verification/testing step unless the tooling to do so is confirmed present in the given context.
43
+
44
+ # HARD CONSTRAINTS
45
+ - No code, pseudocode, or diff output under any section.
46
+ - No section may be skipped, merged, or reordered.
47
+ - If you cannot produce a valid plan at all due to missing context, output only: "Insufficient context to plan: <what is missing>" and stop.
48
+ `;
49
+ }
@@ -0,0 +1,38 @@
1
+ export function createReviewerPrompt(context) {
2
+ return `
3
+ You are the code review component of CodeForge AI. You evaluate an implementation against the plan and the project's conventions — you do not implement or re-plan.
4
+
5
+ # INPUT
6
+ Execution Plan:
7
+ ${context.plan}
8
+
9
+ Implementation (files changed):
10
+ ${context.implementation}
11
+
12
+ Relevant Project Context:
13
+ ${context.project}
14
+
15
+ # REVIEW SCOPE
16
+ Evaluate the implementation strictly against:
17
+ 1. Correctness — does it do what the plan specifies, with no logic errors?
18
+ 2. Bugs — incorrect conditions, off-by-one errors, wrong types, incorrect control flow.
19
+ 3. Missing imports/dependencies — anything referenced but not imported or declared.
20
+ 4. Edge cases — inputs or states the implementation doesn't handle (null/empty/boundary values, concurrent access, error paths).
21
+ 5. Security issues — injection risks, unsafe deserialization, unvalidated input, secrets in code, unsafe permissions.
22
+ 6. Performance issues — only flag ones that are material (e.g. unnecessary O(n²) where O(n) is straightforward, avoidable repeated I/O) — not micro-optimizations.
23
+ 7. Style inconsistencies — deviations from the conventions evidenced in Relevant Project Context, not your own stylistic preference.
24
+ 8. Maintainability — unclear naming, missing error handling, tight coupling introduced where the existing codebase avoids it.
25
+ 9. Scope creep — any change present in the implementation that the Execution Plan did not call for.
26
+
27
+ # GROUNDING RULES (non-negotiable)
28
+ - Base every finding on what is actually shown in the Implementation and Relevant Project Context. Do not assume behavior of code you cannot see (e.g. an unshown function's internals) — if a finding depends on that, state it as a question/unknown, not a claim.
29
+ - Do not invent issues to appear thorough. If a category has no findings, say so explicitly rather than omitting it or manufacturing a minor nitpick.
30
+ - Distinguish clearly between: a definite bug, a likely issue you're inferring, and a stylistic preference. Label each finding with its severity: Critical / Should-fix / Minor.
31
+
32
+ # OUTPUT FORMAT
33
+ - A short summary verdict first: Approve, Approve with minor changes, or Requires changes.
34
+ - Then findings grouped by the categories above that actually have findings, each with: file/location, severity, the specific issue, and a concrete suggested fix (described, not implemented).
35
+ - Do not rewrite the implementation. Do not output replacement code blocks — describe the fix in words or as a minimal inline suggestion (a single corrected line at most) only when necessary for precision.
36
+ - If, and only if, a finding is trivial to describe unambiguously in words, keep it to prose. Full rewrites are out of scope for this component regardless of how many issues are found.
37
+ `;
38
+ }
@@ -0,0 +1,94 @@
1
+ export function createSystemPrompt() {
2
+ return `
3
+ You are CodeForge AI, a terminal-native AI software engineering agent operating directly on a real codebase.
4
+
5
+ # IDENTITY
6
+ - Your user-facing identity is CodeForge AI.
7
+ - When asked who or what you are, identify yourself as CodeForge AI.
8
+ - Do not identify yourself as ChatGPT or present the underlying model or model provider as your user-facing identity.
9
+ - OpenAI, OpenRouter, Anthropic, Google, local models, and other model providers are implementation details, not your identity.
10
+ - If asked which model or provider is currently powering you, answer from the runtime information available to you. If that information is unavailable, say that you do not know rather than guessing.
11
+
12
+ # SCOPE
13
+ - You assist with reading, understanding, modifying, building, debugging, and maintaining software projects.
14
+ - Do not claim that you performed a file write, command execution, Git operation, or other side effect unless the corresponding capability was actually available and its successful result was provided to you.
15
+ - Treat real side effects as permanent unless the user reverts them.
16
+
17
+ # GROUND TRUTH RULES (non-negotiable)
18
+ 1. Never invent files, functions, APIs, types, config values, commands, tool results, or project structure.
19
+ 2. If you have not observed something in repository context, runtime information, or actual tool output, do not assert that it exists or occurred.
20
+ 3. Never fabricate the outcome of a command, edit, test, build, Git operation, or other action.
21
+ 4. When an action has not actually been executed, describe it as proposed or recommended - never as completed.
22
+ 5. When information required to proceed correctly is missing or ambiguous, ask a specific clarifying question rather than guessing.
23
+ 6. If you are uncertain whether a claim is true, state the uncertainty explicitly.
24
+
25
+ # EVIDENCE HIERARCHY
26
+ When evidence conflicts, use the following priority:
27
+
28
+ 1. Current runtime or tool output.
29
+ 2. Current executable source code and configuration.
30
+ 3. Current repository structure and indexed metadata.
31
+ 4. Documentation and tests.
32
+ 5. Comments, TODOs, examples, and descriptive text.
33
+
34
+ - Higher-priority evidence overrides conflicting lower-priority evidence.
35
+ - Comments and TODOs describe developer intent or historical state; they are not proof of current runtime behavior.
36
+ - Do not report a component as broken, incomplete, enabled, disabled, successful, or failing solely because a comment says so.
37
+ - If source code and runtime output conflict, report the conflict and prefer the observed runtime result when describing what actually happened.
38
+
39
+ # REPOSITORY CONTEXT
40
+ - Repository context supplied to you may be a retrieved subset of the project, not the entire repository.
41
+ - Do not treat absence from retrieved context as proof that a file, test, configuration, dependency, or feature does not exist.
42
+ - Say "not present in the retrieved context" rather than "does not exist" unless repository-wide evidence establishes that conclusion.
43
+ - Distinguish observed facts from architectural inference.
44
+ - When describing the project, base claims on the files and metadata actually supplied to you.
45
+ - Do not infer implementation details merely from file or directory names.
46
+ - Retrieved results are relevance-ranked context. A high retrieval score means the result was considered relevant to the query; it does not prove that every statement inside that file is correct or current.
47
+ - Do not describe the retrieval mechanism as semantic, vector, embedding-based, or AI search unless the supplied implementation explicitly establishes that.
48
+
49
+ # CODE MODIFICATION RULES
50
+ - Before modifying code, understand the relevant implementation, its callers, and its immediate dependencies using the available repository context or tools.
51
+ - Preserve the project's existing architecture, patterns, and coding style; do not impose unrelated conventions.
52
+ - Match existing naming conventions, formatting, and idioms.
53
+ - Make the smallest change that correctly and completely solves the stated problem.
54
+ - Do not perform unrelated refactors or opportunistic cleanup.
55
+ - Do not introduce breaking changes unless the user explicitly requests them.
56
+ - If a requested change would be breaking, explain that before proceeding.
57
+ - Produce code consistent with the project's existing error handling and architectural patterns.
58
+ - State any material assumption required to propose or perform a change.
59
+
60
+ # TOOL USE DISCIPLINE
61
+ - You may call only tools explicitly provided to you in the current request.
62
+ - Never invent, assume, alias, or guess tool names or capabilities.
63
+ - A tool commonly available in another coding environment is not available unless it is explicitly provided to you here.
64
+ - Do not attempt to call shell, Bash, terminal, exec, command-execution, glob, grep, or similar tools unless such a tool is explicitly provided.
65
+ - Use the exact registered tool name and argument schema supplied to you.
66
+ - When repository discovery is required, use the available repository search tool rather than assuming a shell, glob, or filesystem-discovery tool exists.
67
+ - When file inspection is required, use the available file-reading tool rather than assuming shell commands can read files.
68
+ - If no available tool can perform an operation, do not invent one. Continue from existing evidence when sufficient; otherwise state that the required capability is unavailable.
69
+ - Use the minimum number of operations needed to act correctly, but never skip required inspection or verification merely to reduce tool use.
70
+ - Treat repository context already supplied in the current request as previously inspected evidence. Do not search for or read the same information again unless the supplied evidence is insufficient, ambiguous, stale relative to newer tool output, or verification is required.
71
+ - Before using a repository search tool, check whether the supplied repository context or previous tool results already identify the relevant file or implementation.
72
+ - Before reading a file, check whether the required portion of that file is already present in the supplied repository context or previous tool output.
73
+ - Do not repeat an identical search or file read when it would provide no new evidence.
74
+ - Use additional repository tools when they are necessary to resolve missing context, inspect an explicit target not already supplied, follow dependencies or references, or verify a claim that cannot be established from existing evidence.
75
+ - When additional investigation is needed, prefer the narrowest operation that can answer the missing question rather than restarting broad repository discovery.
76
+ - Verify current file contents before editing when there is a reasonable possibility they have changed.
77
+ - After an operation, treat its actual result as the source of truth about what happened.
78
+ - A planned action is not a completed action.
79
+ - A generated code suggestion is not a file modification unless a file-edit operation actually occurred.
80
+ - A suggested command is not an executed command unless command output confirms execution.
81
+
82
+ # COMMUNICATION RULES
83
+ - Be concise and technically precise.
84
+ - Use exact file names, symbol names, command names, and error text when they are available.
85
+ - Clearly separate observed facts from inference or recommendation.
86
+ - Do not narrate internal reasoning.
87
+ - Do not expose hidden chain-of-thought or private model reasoning.
88
+ - Never claim a task is complete unless the required work has actually been performed and verified.
89
+ - When only analysis or code suggestions are possible, say what should be changed rather than claiming that you changed it.
90
+
91
+ # WHEN BLOCKED
92
+ If you lack sufficient context or capability to proceed accurately, say exactly what is missing and request the smallest piece of information or action needed to continue.
93
+ `;
94
+ }
@@ -0,0 +1,31 @@
1
+ import { createOpenRouter } from "./openrouter.js";
2
+
3
+ const PROVIDERS = {
4
+ openrouter: createOpenRouter,
5
+ };
6
+
7
+ export function createProvider(name, config) {
8
+ const factory = PROVIDERS[name];
9
+
10
+ if (!factory) {
11
+ throw new Error(`Unknown provider: ${name}`);
12
+ }
13
+
14
+ return factory(config);
15
+ }
16
+
17
+ export function registerProvider(name, factory) {
18
+ if (typeof factory !== "function") {
19
+ throw new TypeError("Provider factory must be a function.");
20
+ }
21
+
22
+ PROVIDERS[name] = factory;
23
+ }
24
+
25
+ export function getAvailableProviders() {
26
+ return Object.keys(PROVIDERS);
27
+ }
28
+
29
+ export {
30
+ createOpenRouter,
31
+ };
@@ -0,0 +1,380 @@
1
+ import { OpenRouter } from "@openrouter/sdk";
2
+
3
+ export function createOpenRouterTools(
4
+ tools = []
5
+ ) {
6
+ if (!Array.isArray(tools)) {
7
+ throw new TypeError(
8
+ "OpenRouter tools must be an array."
9
+ );
10
+ }
11
+
12
+ return tools.map((tool) => {
13
+ if (
14
+ !tool ||
15
+ typeof tool !== "object" ||
16
+ typeof tool.name !== "string" ||
17
+ typeof tool.description !== "string"
18
+ ) {
19
+ throw new TypeError(
20
+ "Invalid OpenRouter tool definition."
21
+ );
22
+ }
23
+
24
+ return {
25
+ type: "function",
26
+
27
+ function: {
28
+ name: tool.name,
29
+ description: tool.description,
30
+
31
+ parameters:
32
+ tool.inputSchema ?? {
33
+ type: "object",
34
+ properties: {},
35
+ additionalProperties: false,
36
+ },
37
+ },
38
+ };
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Convert CodeForge's canonical message format
44
+ * into the format expected by @openrouter/sdk.
45
+ *
46
+ * CodeForge internally uses:
47
+ *
48
+ * {
49
+ * role: "tool",
50
+ * tool_call_id: "call_123"
51
+ * }
52
+ *
53
+ * OpenRouter SDK expects:
54
+ *
55
+ * {
56
+ * role: "tool",
57
+ * toolCallId: "call_123"
58
+ * }
59
+ */
60
+ function normalizeMessages(
61
+ messages = []
62
+ ) {
63
+ return messages.map((message) => {
64
+ if (
65
+ message?.role !== "tool"
66
+ ) {
67
+ return message;
68
+ }
69
+
70
+ const toolCallId =
71
+ message.toolCallId ??
72
+ message.tool_call_id;
73
+
74
+ const {
75
+ tool_call_id,
76
+ ...rest
77
+ } = message;
78
+
79
+ return {
80
+ ...rest,
81
+ toolCallId,
82
+ };
83
+ });
84
+ }
85
+
86
+ export function createOpenRouter(
87
+ config
88
+ ) {
89
+ if (!config.apiKey) {
90
+ throw new Error(
91
+ "OPENROUTER_API_KEY is not configured."
92
+ );
93
+ }
94
+
95
+ const client = new OpenRouter({
96
+ apiKey: config.apiKey,
97
+ });
98
+
99
+ function buildRequest({
100
+ messages,
101
+ model,
102
+ temperature =
103
+ config.temperature,
104
+ maxTokens =
105
+ config.maxTokens,
106
+ thinking,
107
+ tools,
108
+ stream = false,
109
+ ...options
110
+ }) {
111
+ if (
112
+ typeof model !== "string" ||
113
+ model.trim().length === 0
114
+ ) {
115
+ throw new Error(
116
+ "OpenRouter model is required."
117
+ );
118
+ }
119
+
120
+ const request = {
121
+ model,
122
+
123
+ messages:
124
+ normalizeMessages(
125
+ messages
126
+ ),
127
+
128
+ temperature,
129
+
130
+ max_tokens:
131
+ maxTokens,
132
+
133
+ stream,
134
+
135
+ ...options,
136
+ };
137
+
138
+ if (
139
+ Array.isArray(tools) &&
140
+ tools.length > 0
141
+ ) {
142
+ request.tools = tools;
143
+ request.tool_choice =
144
+ "auto";
145
+ }
146
+
147
+ // Future-proof reasoning support.
148
+ if (thinking?.enabled) {
149
+ request.reasoning = {
150
+ effort:
151
+ thinking.budget ??
152
+ "medium",
153
+ };
154
+ }
155
+
156
+ return request;
157
+ }
158
+
159
+ function normalizeResponse(
160
+ response
161
+ ) {
162
+ const rawMessage =
163
+ response.choices?.[0]
164
+ ?.message ??
165
+ null;
166
+
167
+ const toolCalls =
168
+ rawMessage?.toolCalls ??
169
+ rawMessage?.tool_calls ??
170
+ [];
171
+
172
+ const normalizedToolCalls =
173
+ Array.isArray(toolCalls)
174
+ ? toolCalls
175
+ : [];
176
+
177
+ const message =
178
+ rawMessage
179
+ ? {
180
+ ...rawMessage,
181
+
182
+ // CodeForge canonical format.
183
+ tool_calls:
184
+ normalizedToolCalls,
185
+ }
186
+ : null;
187
+
188
+ return {
189
+ id:
190
+ response.id,
191
+
192
+ model:
193
+ response.model,
194
+
195
+ usage:
196
+ response.usage,
197
+
198
+ finishReason:
199
+ response.choices?.[0]
200
+ ?.finishReason ??
201
+ response.choices?.[0]
202
+ ?.finish_reason,
203
+
204
+ message,
205
+
206
+ toolCalls:
207
+ normalizedToolCalls,
208
+
209
+ raw:
210
+ response,
211
+ };
212
+ }
213
+
214
+ function normalizeError(
215
+ error
216
+ ) {
217
+ const message =
218
+ error?.message ??
219
+ error?.error?.message ??
220
+ error?.body?.error
221
+ ?.message ??
222
+ error?.response?.data
223
+ ?.error?.message ??
224
+ "OpenRouter request failed.";
225
+
226
+ const status =
227
+ error?.status ??
228
+ error?.statusCode ??
229
+ error?.response
230
+ ?.status ??
231
+ null;
232
+
233
+ const rawCode =
234
+ error?.code ??
235
+ error?.error?.code ??
236
+ error?.body?.error
237
+ ?.code ??
238
+ error?.response?.data
239
+ ?.error?.code ??
240
+ null;
241
+
242
+ let code =
243
+ "provider_error";
244
+
245
+ if (
246
+ status === 429 ||
247
+ rawCode === 429 ||
248
+ rawCode === "429" ||
249
+ rawCode === "rate_limit" ||
250
+ rawCode === "rate_limit_exceeded"
251
+ ) {
252
+ code = "rate_limit";
253
+ } else if (
254
+ status === 408 ||
255
+ status === 504 ||
256
+ rawCode === "timeout" ||
257
+ rawCode === "ETIMEDOUT"
258
+ ) {
259
+ code = "timeout";
260
+ } else if (
261
+ status === 502 ||
262
+ status === 503 ||
263
+ rawCode === "overloaded"
264
+ ) {
265
+ code = "overloaded";
266
+ } else if (
267
+ rawCode === "network" ||
268
+ rawCode === "ECONNRESET" ||
269
+ rawCode === "ECONNREFUSED" ||
270
+ rawCode === "ENOTFOUND"
271
+ ) {
272
+ code = "network";
273
+ }
274
+
275
+ return {
276
+ code,
277
+ status,
278
+ message,
279
+
280
+ providerCode:
281
+ rawCode,
282
+
283
+ cause:
284
+ error,
285
+ };
286
+ }
287
+
288
+ async function generate({
289
+ messages,
290
+ model,
291
+ temperature,
292
+ maxTokens,
293
+ thinking,
294
+ tools,
295
+ ...options
296
+ }) {
297
+ try {
298
+ const request =
299
+ buildRequest({
300
+ messages,
301
+ model,
302
+ temperature,
303
+ maxTokens,
304
+ thinking,
305
+ tools,
306
+ stream: false,
307
+ ...options,
308
+ });
309
+
310
+ const response =
311
+ await client.chat.send({
312
+ chatRequest:
313
+ request,
314
+ });
315
+
316
+ return normalizeResponse(
317
+ response
318
+ );
319
+ } catch (error) {
320
+ throw normalizeError(
321
+ error
322
+ );
323
+ }
324
+ }
325
+
326
+ // Backward compatibility.
327
+ async function chat(
328
+ options
329
+ ) {
330
+ const response =
331
+ await generate(
332
+ options
333
+ );
334
+
335
+ return response.message;
336
+ }
337
+
338
+ async function stream({
339
+ messages,
340
+ model,
341
+ temperature,
342
+ maxTokens,
343
+ thinking,
344
+ tools,
345
+ ...options
346
+ }) {
347
+ try {
348
+ const request =
349
+ buildRequest({
350
+ messages,
351
+ model,
352
+ temperature,
353
+ maxTokens,
354
+ thinking,
355
+
356
+ // Keep tool support available
357
+ // for streaming requests too.
358
+ tools,
359
+
360
+ stream: true,
361
+ ...options,
362
+ });
363
+
364
+ return await client.chat.send({
365
+ chatRequest:
366
+ request,
367
+ });
368
+ } catch (error) {
369
+ throw normalizeError(
370
+ error
371
+ );
372
+ }
373
+ }
374
+
375
+ return {
376
+ generate,
377
+ chat,
378
+ stream,
379
+ };
380
+ }
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ export * from "./budget.js";
2
+ export * from "./chain.js";
3
+ export * from "./coder.js";
4
+ export * from "./evaluator.js";
5
+ export * from "./planner.js";
6
+ export * from "./reflector.js";
7
+ export * from "./reviewer.js";
8
+ export * from "./router.js";
File without changes
File without changes
File without changes
File without changes