@chat-js/cli 0.2.1 → 0.4.0
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.
- package/dist/index.js +216 -171
- package/package.json +1 -1
- package/templates/chat-app/CHANGELOG.md +19 -0
- package/templates/chat-app/app/(chat)/actions.ts +9 -9
- package/templates/chat-app/app/(chat)/api/chat/prepare/route.ts +94 -0
- package/templates/chat-app/app/(chat)/api/chat/route.ts +97 -14
- package/templates/chat-app/chat.config.ts +144 -156
- package/templates/chat-app/components/chat-sync.tsx +6 -3
- package/templates/chat-app/components/feedback-actions.tsx +7 -3
- package/templates/chat-app/components/message-editor.tsx +8 -3
- package/templates/chat-app/components/message-siblings.tsx +14 -1
- package/templates/chat-app/components/model-selector.tsx +669 -407
- package/templates/chat-app/components/multimodal-input.tsx +252 -18
- package/templates/chat-app/components/parallel-response-cards.tsx +157 -0
- package/templates/chat-app/components/part/text-message-part.tsx +9 -5
- package/templates/chat-app/components/retry-button.tsx +25 -8
- package/templates/chat-app/components/user-message.tsx +136 -125
- package/templates/chat-app/hooks/chat-sync-hooks.ts +11 -0
- package/templates/chat-app/hooks/use-navigate-to-message.ts +39 -0
- package/templates/chat-app/lib/ai/gateway-model-defaults.ts +154 -100
- package/templates/chat-app/lib/ai/gateways/openrouter-gateway.ts +2 -2
- package/templates/chat-app/lib/ai/tools/generate-image.ts +9 -2
- package/templates/chat-app/lib/ai/tools/generate-video.ts +3 -0
- package/templates/chat-app/lib/ai/types.ts +74 -3
- package/templates/chat-app/lib/config-schema.ts +131 -132
- package/templates/chat-app/lib/config.ts +2 -2
- package/templates/chat-app/lib/db/migrations/0044_gray_red_shift.sql +5 -0
- package/templates/chat-app/lib/db/migrations/meta/0044_snapshot.json +1567 -0
- package/templates/chat-app/lib/db/migrations/meta/_journal.json +8 -1
- package/templates/chat-app/lib/db/queries.ts +84 -4
- package/templates/chat-app/lib/db/schema.ts +4 -1
- package/templates/chat-app/lib/message-conversion.ts +14 -2
- package/templates/chat-app/lib/stores/hooks-threads.ts +37 -1
- package/templates/chat-app/lib/stores/with-threads.test.ts +137 -0
- package/templates/chat-app/lib/stores/with-threads.ts +157 -4
- package/templates/chat-app/lib/thread-utils.ts +23 -2
- package/templates/chat-app/package.json +1 -1
- package/templates/chat-app/providers/chat-input-provider.tsx +40 -2
- package/templates/chat-app/scripts/db-branch-delete.sh +7 -1
- package/templates/chat-app/scripts/db-branch-use.sh +7 -1
- package/templates/chat-app/scripts/with-db.sh +7 -1
- package/templates/chat-app/vitest.config.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -3914,7 +3914,7 @@ var {
|
|
|
3914
3914
|
// package.json
|
|
3915
3915
|
var package_default = {
|
|
3916
3916
|
name: "@chat-js/cli",
|
|
3917
|
-
version: "0.
|
|
3917
|
+
version: "0.4.0",
|
|
3918
3918
|
description: "CLI for creating and extending ChatJS apps",
|
|
3919
3919
|
license: "Apache-2.0",
|
|
3920
3920
|
repository: {
|
|
@@ -17611,6 +17611,71 @@ var add = new Command().name("add").description("add a component or feature to a
|
|
|
17611
17611
|
}
|
|
17612
17612
|
});
|
|
17613
17613
|
|
|
17614
|
+
// src/commands/config.ts
|
|
17615
|
+
import { spawn } from "node:child_process";
|
|
17616
|
+
import path from "node:path";
|
|
17617
|
+
|
|
17618
|
+
// src/utils/get-package-manager.ts
|
|
17619
|
+
function inferPackageManager() {
|
|
17620
|
+
const ua = process.env.npm_config_user_agent ?? "";
|
|
17621
|
+
if (ua.startsWith("pnpm/"))
|
|
17622
|
+
return "pnpm";
|
|
17623
|
+
if (ua.startsWith("yarn/"))
|
|
17624
|
+
return "yarn";
|
|
17625
|
+
if (ua.startsWith("npm/"))
|
|
17626
|
+
return "npm";
|
|
17627
|
+
if (ua.startsWith("bun/"))
|
|
17628
|
+
return "bun";
|
|
17629
|
+
return "bun";
|
|
17630
|
+
}
|
|
17631
|
+
|
|
17632
|
+
// src/commands/config.ts
|
|
17633
|
+
var EVAL_SCRIPT = `
|
|
17634
|
+
import userConfig from "./chat.config.ts";
|
|
17635
|
+
import { applyDefaults } from "./lib/config-schema";
|
|
17636
|
+
console.log(JSON.stringify(applyDefaults(userConfig), null, 2));
|
|
17637
|
+
`;
|
|
17638
|
+
function getTsEvalCommand(pm) {
|
|
17639
|
+
switch (pm) {
|
|
17640
|
+
case "bun":
|
|
17641
|
+
return ["bun", ["--eval", EVAL_SCRIPT]];
|
|
17642
|
+
case "pnpm":
|
|
17643
|
+
return ["pnpm", ["dlx", "tsx", "--eval", EVAL_SCRIPT]];
|
|
17644
|
+
case "yarn":
|
|
17645
|
+
return ["yarn", ["dlx", "tsx", "--eval", EVAL_SCRIPT]];
|
|
17646
|
+
default:
|
|
17647
|
+
return ["npx", ["tsx", "--eval", EVAL_SCRIPT]];
|
|
17648
|
+
}
|
|
17649
|
+
}
|
|
17650
|
+
var config2 = new Command().name("config").description("print the resolved configuration for the current ChatJS project").option("-c, --cwd <cwd>", "the working directory (defaults to current directory)", process.cwd()).action(async (opts) => {
|
|
17651
|
+
try {
|
|
17652
|
+
const cwd = path.resolve(opts.cwd);
|
|
17653
|
+
const pm = inferPackageManager();
|
|
17654
|
+
const [cmd, args] = getTsEvalCommand(pm);
|
|
17655
|
+
await new Promise((resolve, reject) => {
|
|
17656
|
+
const child = spawn(cmd, args, {
|
|
17657
|
+
cwd,
|
|
17658
|
+
stdio: ["ignore", "inherit", "pipe"]
|
|
17659
|
+
});
|
|
17660
|
+
const stderr = [];
|
|
17661
|
+
child.stderr?.on("data", (data) => stderr.push(String(data)));
|
|
17662
|
+
child.on("error", (err) => {
|
|
17663
|
+
reject(new Error(`Could not spawn ${cmd}. Make sure ${pm} is installed.
|
|
17664
|
+
${err.message}`));
|
|
17665
|
+
});
|
|
17666
|
+
child.on("close", (code) => {
|
|
17667
|
+
if (code === 0)
|
|
17668
|
+
resolve();
|
|
17669
|
+
else
|
|
17670
|
+
reject(new Error(`Failed to resolve config:
|
|
17671
|
+
${stderr.join("").trim()}`));
|
|
17672
|
+
});
|
|
17673
|
+
});
|
|
17674
|
+
} catch (error48) {
|
|
17675
|
+
handleError(error48);
|
|
17676
|
+
}
|
|
17677
|
+
});
|
|
17678
|
+
|
|
17614
17679
|
// src/commands/create.ts
|
|
17615
17680
|
import { readFile, writeFile } from "node:fs/promises";
|
|
17616
17681
|
import { join as join2, resolve as resolve2 } from "node:path";
|
|
@@ -18661,7 +18726,7 @@ ${l}
|
|
|
18661
18726
|
} }).prompt();
|
|
18662
18727
|
|
|
18663
18728
|
// ../../apps/chat/lib/ai/gateway-model-defaults.ts
|
|
18664
|
-
var
|
|
18729
|
+
var vercelDefaults = {
|
|
18665
18730
|
providerOrder: ["openai", "google", "anthropic"],
|
|
18666
18731
|
disabledModels: [],
|
|
18667
18732
|
curatedDefaults: [
|
|
@@ -18684,36 +18749,66 @@ var multiProviderDefaults = {
|
|
|
18684
18749
|
chatImageCompatible: "openai/gpt-4o-mini"
|
|
18685
18750
|
},
|
|
18686
18751
|
tools: {
|
|
18687
|
-
webSearch: {
|
|
18688
|
-
|
|
18689
|
-
},
|
|
18690
|
-
|
|
18691
|
-
enabled: false
|
|
18692
|
-
},
|
|
18693
|
-
codeExecution: {
|
|
18694
|
-
enabled: false
|
|
18695
|
-
},
|
|
18696
|
-
mcp: {
|
|
18697
|
-
enabled: false
|
|
18698
|
-
},
|
|
18752
|
+
webSearch: { enabled: false },
|
|
18753
|
+
urlRetrieval: { enabled: false },
|
|
18754
|
+
codeExecution: { enabled: false },
|
|
18755
|
+
mcp: { enabled: false },
|
|
18699
18756
|
followupSuggestions: {
|
|
18700
18757
|
enabled: false,
|
|
18701
18758
|
default: "google/gemini-2.5-flash-lite"
|
|
18702
18759
|
},
|
|
18703
|
-
text: {
|
|
18704
|
-
|
|
18705
|
-
},
|
|
18706
|
-
|
|
18707
|
-
|
|
18708
|
-
|
|
18709
|
-
},
|
|
18710
|
-
code: {
|
|
18711
|
-
edits: "openai/gpt-5-mini"
|
|
18712
|
-
},
|
|
18713
|
-
image: {
|
|
18760
|
+
text: { polish: "openai/gpt-5-mini" },
|
|
18761
|
+
sheet: { format: "openai/gpt-5-mini", analyze: "openai/gpt-5-mini" },
|
|
18762
|
+
code: { edits: "openai/gpt-5-mini" },
|
|
18763
|
+
image: { enabled: false, default: "google/gemini-3-pro-image" },
|
|
18764
|
+
video: { enabled: false, default: "xai/grok-imagine-video" },
|
|
18765
|
+
deepResearch: {
|
|
18714
18766
|
enabled: false,
|
|
18715
|
-
|
|
18767
|
+
defaultModel: "google/gemini-2.5-flash-lite",
|
|
18768
|
+
finalReportModel: "google/gemini-3-flash",
|
|
18769
|
+
allowClarification: true,
|
|
18770
|
+
maxResearcherIterations: 1,
|
|
18771
|
+
maxConcurrentResearchUnits: 2,
|
|
18772
|
+
maxSearchQueries: 2
|
|
18773
|
+
}
|
|
18774
|
+
}
|
|
18775
|
+
};
|
|
18776
|
+
var openrouterDefaults = {
|
|
18777
|
+
providerOrder: ["openai", "google", "anthropic"],
|
|
18778
|
+
disabledModels: [],
|
|
18779
|
+
curatedDefaults: [
|
|
18780
|
+
"openai/gpt-5-nano",
|
|
18781
|
+
"openai/gpt-5-mini",
|
|
18782
|
+
"openai/gpt-5.2",
|
|
18783
|
+
"openai/gpt-5.2-chat",
|
|
18784
|
+
"google/gemini-2.5-flash-lite",
|
|
18785
|
+
"google/gemini-3-flash",
|
|
18786
|
+
"google/gemini-3-pro-preview",
|
|
18787
|
+
"anthropic/claude-sonnet-4.5",
|
|
18788
|
+
"anthropic/claude-opus-4.5",
|
|
18789
|
+
"xai/grok-4"
|
|
18790
|
+
],
|
|
18791
|
+
anonymousModels: ["google/gemini-2.5-flash-lite", "openai/gpt-5-nano"],
|
|
18792
|
+
workflows: {
|
|
18793
|
+
chat: "openai/gpt-5-mini",
|
|
18794
|
+
title: "openai/gpt-5-nano",
|
|
18795
|
+
pdf: "openai/gpt-5-mini",
|
|
18796
|
+
chatImageCompatible: "openai/gpt-4o-mini"
|
|
18797
|
+
},
|
|
18798
|
+
tools: {
|
|
18799
|
+
webSearch: { enabled: false },
|
|
18800
|
+
urlRetrieval: { enabled: false },
|
|
18801
|
+
codeExecution: { enabled: false },
|
|
18802
|
+
mcp: { enabled: false },
|
|
18803
|
+
followupSuggestions: {
|
|
18804
|
+
enabled: false,
|
|
18805
|
+
default: "google/gemini-2.5-flash-lite"
|
|
18716
18806
|
},
|
|
18807
|
+
text: { polish: "openai/gpt-5-mini" },
|
|
18808
|
+
sheet: { format: "openai/gpt-5-mini", analyze: "openai/gpt-5-mini" },
|
|
18809
|
+
code: { edits: "openai/gpt-5-mini" },
|
|
18810
|
+
image: { enabled: false },
|
|
18811
|
+
video: { enabled: false },
|
|
18717
18812
|
deepResearch: {
|
|
18718
18813
|
enabled: false,
|
|
18719
18814
|
defaultModel: "google/gemini-2.5-flash-lite",
|
|
@@ -18725,7 +18820,7 @@ var multiProviderDefaults = {
|
|
|
18725
18820
|
}
|
|
18726
18821
|
}
|
|
18727
18822
|
};
|
|
18728
|
-
var
|
|
18823
|
+
var openaiDefaults = {
|
|
18729
18824
|
providerOrder: ["openai"],
|
|
18730
18825
|
disabledModels: [],
|
|
18731
18826
|
curatedDefaults: [
|
|
@@ -18742,36 +18837,54 @@ var openaiOnlyDefaults = {
|
|
|
18742
18837
|
chatImageCompatible: "gpt-4o-mini"
|
|
18743
18838
|
},
|
|
18744
18839
|
tools: {
|
|
18745
|
-
webSearch: {
|
|
18746
|
-
|
|
18747
|
-
},
|
|
18748
|
-
|
|
18749
|
-
|
|
18750
|
-
},
|
|
18751
|
-
|
|
18752
|
-
|
|
18753
|
-
},
|
|
18754
|
-
|
|
18755
|
-
|
|
18756
|
-
},
|
|
18757
|
-
followupSuggestions: {
|
|
18758
|
-
enabled: false,
|
|
18759
|
-
default: "gpt-5-nano"
|
|
18760
|
-
},
|
|
18761
|
-
text: {
|
|
18762
|
-
polish: "gpt-5-mini"
|
|
18763
|
-
},
|
|
18764
|
-
sheet: {
|
|
18765
|
-
format: "gpt-5-mini",
|
|
18766
|
-
analyze: "gpt-5-mini"
|
|
18767
|
-
},
|
|
18768
|
-
code: {
|
|
18769
|
-
edits: "gpt-5-mini"
|
|
18770
|
-
},
|
|
18771
|
-
image: {
|
|
18840
|
+
webSearch: { enabled: false },
|
|
18841
|
+
urlRetrieval: { enabled: false },
|
|
18842
|
+
codeExecution: { enabled: false },
|
|
18843
|
+
mcp: { enabled: false },
|
|
18844
|
+
followupSuggestions: { enabled: false, default: "gpt-5-nano" },
|
|
18845
|
+
text: { polish: "gpt-5-mini" },
|
|
18846
|
+
sheet: { format: "gpt-5-mini", analyze: "gpt-5-mini" },
|
|
18847
|
+
code: { edits: "gpt-5-mini" },
|
|
18848
|
+
image: { enabled: false },
|
|
18849
|
+
video: { enabled: false },
|
|
18850
|
+
deepResearch: {
|
|
18772
18851
|
enabled: false,
|
|
18773
|
-
|
|
18774
|
-
|
|
18852
|
+
defaultModel: "gpt-5-nano",
|
|
18853
|
+
finalReportModel: "gpt-5-mini",
|
|
18854
|
+
allowClarification: true,
|
|
18855
|
+
maxResearcherIterations: 1,
|
|
18856
|
+
maxConcurrentResearchUnits: 2,
|
|
18857
|
+
maxSearchQueries: 2
|
|
18858
|
+
}
|
|
18859
|
+
}
|
|
18860
|
+
};
|
|
18861
|
+
var openaiCompatibleDefaults = {
|
|
18862
|
+
providerOrder: ["openai"],
|
|
18863
|
+
disabledModels: [],
|
|
18864
|
+
curatedDefaults: [
|
|
18865
|
+
"gpt-5-nano",
|
|
18866
|
+
"gpt-5-mini",
|
|
18867
|
+
"gpt-5.2",
|
|
18868
|
+
"gpt-5.2-chat-latest"
|
|
18869
|
+
],
|
|
18870
|
+
anonymousModels: ["gpt-5-nano"],
|
|
18871
|
+
workflows: {
|
|
18872
|
+
chat: "gpt-5-mini",
|
|
18873
|
+
title: "gpt-5-nano",
|
|
18874
|
+
pdf: "gpt-5-mini",
|
|
18875
|
+
chatImageCompatible: "gpt-4o-mini"
|
|
18876
|
+
},
|
|
18877
|
+
tools: {
|
|
18878
|
+
webSearch: { enabled: false },
|
|
18879
|
+
urlRetrieval: { enabled: false },
|
|
18880
|
+
codeExecution: { enabled: false },
|
|
18881
|
+
mcp: { enabled: false },
|
|
18882
|
+
followupSuggestions: { enabled: false, default: "gpt-5-nano" },
|
|
18883
|
+
text: { polish: "gpt-5-mini" },
|
|
18884
|
+
sheet: { format: "gpt-5-mini", analyze: "gpt-5-mini" },
|
|
18885
|
+
code: { edits: "gpt-5-mini" },
|
|
18886
|
+
image: { enabled: false },
|
|
18887
|
+
video: { enabled: false },
|
|
18775
18888
|
deepResearch: {
|
|
18776
18889
|
enabled: false,
|
|
18777
18890
|
defaultModel: "gpt-5-nano",
|
|
@@ -18784,10 +18897,10 @@ var openaiOnlyDefaults = {
|
|
|
18784
18897
|
}
|
|
18785
18898
|
};
|
|
18786
18899
|
var GATEWAY_MODEL_DEFAULTS = {
|
|
18787
|
-
vercel:
|
|
18788
|
-
openrouter:
|
|
18789
|
-
openai:
|
|
18790
|
-
"openai-compatible":
|
|
18900
|
+
vercel: vercelDefaults,
|
|
18901
|
+
openrouter: openrouterDefaults,
|
|
18902
|
+
openai: openaiDefaults,
|
|
18903
|
+
"openai-compatible": openaiCompatibleDefaults
|
|
18791
18904
|
};
|
|
18792
18905
|
|
|
18793
18906
|
// ../../apps/chat/lib/config-schema.ts
|
|
@@ -18850,14 +18963,26 @@ function createAiSchema(g) {
|
|
|
18850
18963
|
code: exports_external.object({
|
|
18851
18964
|
edits: gatewayModelId()
|
|
18852
18965
|
}),
|
|
18853
|
-
image: exports_external.
|
|
18854
|
-
|
|
18855
|
-
|
|
18856
|
-
|
|
18857
|
-
|
|
18858
|
-
|
|
18859
|
-
|
|
18860
|
-
|
|
18966
|
+
image: exports_external.discriminatedUnion("enabled", [
|
|
18967
|
+
exports_external.object({
|
|
18968
|
+
enabled: exports_external.literal(true),
|
|
18969
|
+
default: gatewayImageModelId()
|
|
18970
|
+
}),
|
|
18971
|
+
exports_external.object({
|
|
18972
|
+
enabled: exports_external.literal(false),
|
|
18973
|
+
default: gatewayImageModelId().optional()
|
|
18974
|
+
})
|
|
18975
|
+
]),
|
|
18976
|
+
video: exports_external.discriminatedUnion("enabled", [
|
|
18977
|
+
exports_external.object({
|
|
18978
|
+
enabled: exports_external.literal(true),
|
|
18979
|
+
default: gatewayVideoModelId()
|
|
18980
|
+
}),
|
|
18981
|
+
exports_external.object({
|
|
18982
|
+
enabled: exports_external.literal(false),
|
|
18983
|
+
default: gatewayVideoModelId().optional()
|
|
18984
|
+
})
|
|
18985
|
+
]),
|
|
18861
18986
|
deepResearch: deepResearchToolConfigSchema.extend({
|
|
18862
18987
|
enabled: exports_external.boolean(),
|
|
18863
18988
|
defaultModel: gatewayModelId(),
|
|
@@ -18879,72 +19004,7 @@ var aiConfigSchema = exports_external.discriminatedUnion("gateway", [
|
|
|
18879
19004
|
gatewaySchemaMap["openai-compatible"]
|
|
18880
19005
|
]).default({
|
|
18881
19006
|
gateway: DEFAULT_GATEWAY,
|
|
18882
|
-
|
|
18883
|
-
disabledModels: [],
|
|
18884
|
-
curatedDefaults: [
|
|
18885
|
-
"openai/gpt-5-nano",
|
|
18886
|
-
"openai/gpt-5-mini",
|
|
18887
|
-
"openai/gpt-5.2",
|
|
18888
|
-
"openai/gpt-5.2-chat",
|
|
18889
|
-
"google/gemini-2.5-flash-lite",
|
|
18890
|
-
"google/gemini-3-flash",
|
|
18891
|
-
"google/gemini-3-pro-preview",
|
|
18892
|
-
"anthropic/claude-sonnet-4.5",
|
|
18893
|
-
"anthropic/claude-opus-4.5",
|
|
18894
|
-
"xai/grok-4"
|
|
18895
|
-
],
|
|
18896
|
-
anonymousModels: ["google/gemini-2.5-flash-lite", "openai/gpt-5-nano"],
|
|
18897
|
-
workflows: {
|
|
18898
|
-
chat: "openai/gpt-5-mini",
|
|
18899
|
-
title: "openai/gpt-5-nano",
|
|
18900
|
-
pdf: "openai/gpt-5-mini",
|
|
18901
|
-
chatImageCompatible: "openai/gpt-4o-mini"
|
|
18902
|
-
},
|
|
18903
|
-
tools: {
|
|
18904
|
-
webSearch: {
|
|
18905
|
-
enabled: false
|
|
18906
|
-
},
|
|
18907
|
-
urlRetrieval: {
|
|
18908
|
-
enabled: false
|
|
18909
|
-
},
|
|
18910
|
-
codeExecution: {
|
|
18911
|
-
enabled: false
|
|
18912
|
-
},
|
|
18913
|
-
mcp: {
|
|
18914
|
-
enabled: false
|
|
18915
|
-
},
|
|
18916
|
-
followupSuggestions: {
|
|
18917
|
-
enabled: false,
|
|
18918
|
-
default: "google/gemini-2.5-flash-lite"
|
|
18919
|
-
},
|
|
18920
|
-
text: {
|
|
18921
|
-
polish: "openai/gpt-5-mini"
|
|
18922
|
-
},
|
|
18923
|
-
sheet: {
|
|
18924
|
-
format: "openai/gpt-5-mini",
|
|
18925
|
-
analyze: "openai/gpt-5-mini"
|
|
18926
|
-
},
|
|
18927
|
-
code: {
|
|
18928
|
-
edits: "openai/gpt-5-mini"
|
|
18929
|
-
},
|
|
18930
|
-
image: {
|
|
18931
|
-
enabled: false,
|
|
18932
|
-
default: "google/gemini-3-pro-image"
|
|
18933
|
-
},
|
|
18934
|
-
video: {
|
|
18935
|
-
enabled: false,
|
|
18936
|
-
default: "xai/grok-imagine-video"
|
|
18937
|
-
},
|
|
18938
|
-
deepResearch: {
|
|
18939
|
-
enabled: false,
|
|
18940
|
-
defaultModel: "google/gemini-2.5-flash-lite",
|
|
18941
|
-
finalReportModel: "google/gemini-3-flash",
|
|
18942
|
-
allowClarification: true,
|
|
18943
|
-
maxResearcherIterations: 1,
|
|
18944
|
-
maxConcurrentResearchUnits: 2,
|
|
18945
|
-
maxSearchQueries: 2
|
|
18946
|
-
}
|
|
18947
|
-
}
|
|
19007
|
+
...GATEWAY_MODEL_DEFAULTS[DEFAULT_GATEWAY]
|
|
18948
19008
|
});
|
|
18949
19009
|
var pricingConfigSchema = exports_external.object({
|
|
18950
19010
|
currency: exports_external.string().optional(),
|
|
@@ -18991,9 +19051,11 @@ var attachmentsConfigSchema = exports_external.object({
|
|
|
18991
19051
|
}
|
|
18992
19052
|
});
|
|
18993
19053
|
var featuresConfigSchema = exports_external.object({
|
|
18994
|
-
attachments: exports_external.boolean().describe("File attachments (requires BLOB_READ_WRITE_TOKEN)")
|
|
19054
|
+
attachments: exports_external.boolean().describe("File attachments (requires BLOB_READ_WRITE_TOKEN)"),
|
|
19055
|
+
parallelResponses: exports_external.boolean().default(true).describe("Send one message to multiple models simultaneously")
|
|
18995
19056
|
}).default({
|
|
18996
|
-
attachments: false
|
|
19057
|
+
attachments: false,
|
|
19058
|
+
parallelResponses: true
|
|
18997
19059
|
});
|
|
18998
19060
|
var authenticationConfigSchema = exports_external.object({
|
|
18999
19061
|
google: exports_external.boolean().describe("Google OAuth (requires AUTH_GOOGLE_ID + AUTH_GOOGLE_SECRET)"),
|
|
@@ -19074,8 +19136,8 @@ function extractDescriptions(schema, prefix = "", result = new Map) {
|
|
|
19074
19136
|
if (unwrapped instanceof exports_external.ZodObject) {
|
|
19075
19137
|
const shape = unwrapped._zod.def.shape;
|
|
19076
19138
|
for (const [key, propSchema] of Object.entries(shape)) {
|
|
19077
|
-
const
|
|
19078
|
-
extractDescriptions(propSchema,
|
|
19139
|
+
const path2 = prefix ? `${prefix}.${key}` : key;
|
|
19140
|
+
extractDescriptions(propSchema, path2, result);
|
|
19079
19141
|
}
|
|
19080
19142
|
}
|
|
19081
19143
|
return result;
|
|
@@ -19117,11 +19179,11 @@ ${spaces}}`;
|
|
|
19117
19179
|
function generateConfig(obj, indent, pathPrefix, descs) {
|
|
19118
19180
|
const spaces = " ".repeat(indent);
|
|
19119
19181
|
return Object.entries(obj).map(([key, value]) => {
|
|
19120
|
-
const
|
|
19121
|
-
const desc = descs.get(
|
|
19182
|
+
const path2 = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
19183
|
+
const desc = descs.get(path2);
|
|
19122
19184
|
const comment = desc ? ` // ${desc}` : "";
|
|
19123
19185
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
19124
|
-
const nested = generateConfig(value, indent + 1,
|
|
19186
|
+
const nested = generateConfig(value, indent + 1, path2, descs);
|
|
19125
19187
|
return `${spaces}${formatKey(key)}: {
|
|
19126
19188
|
${nested}
|
|
19127
19189
|
${spaces}},`;
|
|
@@ -19131,7 +19193,6 @@ ${spaces}},`;
|
|
|
19131
19193
|
`);
|
|
19132
19194
|
}
|
|
19133
19195
|
function buildConfigTs(input) {
|
|
19134
|
-
const modelDefaults = GATEWAY_MODEL_DEFAULTS[input.gateway];
|
|
19135
19196
|
const fullConfig = {
|
|
19136
19197
|
appPrefix: input.appPrefix,
|
|
19137
19198
|
appName: input.appName,
|
|
@@ -19160,7 +19221,7 @@ function buildConfigTs(input) {
|
|
|
19160
19221
|
terms: { title: "Terms of Service" }
|
|
19161
19222
|
},
|
|
19162
19223
|
authentication: input.auth,
|
|
19163
|
-
|
|
19224
|
+
ai: { gateway: input.gateway },
|
|
19164
19225
|
anonymous: {
|
|
19165
19226
|
credits: 10,
|
|
19166
19227
|
availableTools: [],
|
|
@@ -19177,15 +19238,9 @@ function buildConfigTs(input) {
|
|
|
19177
19238
|
"image/jpeg": [".jpg", ".jpeg"],
|
|
19178
19239
|
"application/pdf": [".pdf"]
|
|
19179
19240
|
}
|
|
19180
|
-
},
|
|
19181
|
-
deepResearch: {
|
|
19182
|
-
allowClarification: true,
|
|
19183
|
-
maxResearcherIterations: 1,
|
|
19184
|
-
maxConcurrentResearchUnits: 2,
|
|
19185
|
-
maxSearchQueries: 2
|
|
19186
19241
|
}
|
|
19187
19242
|
};
|
|
19188
|
-
return `import
|
|
19243
|
+
return `import { defineConfig } from "@/lib/config-schema";
|
|
19189
19244
|
|
|
19190
19245
|
/**
|
|
19191
19246
|
* ChatJS Configuration
|
|
@@ -19193,9 +19248,9 @@ function buildConfigTs(input) {
|
|
|
19193
19248
|
* Edit this file to customize your app.
|
|
19194
19249
|
* @see https://chatjs.dev/docs/reference/config
|
|
19195
19250
|
*/
|
|
19196
|
-
const config
|
|
19251
|
+
const config = defineConfig({
|
|
19197
19252
|
${generateConfig(fullConfig, 1, "", descriptions)}
|
|
19198
|
-
};
|
|
19253
|
+
});
|
|
19199
19254
|
|
|
19200
19255
|
export default config;
|
|
19201
19256
|
`;
|
|
@@ -19299,7 +19354,8 @@ var FEATURE_KEYS = [
|
|
|
19299
19354
|
"mcp",
|
|
19300
19355
|
"imageGeneration",
|
|
19301
19356
|
"attachments",
|
|
19302
|
-
"followupSuggestions"
|
|
19357
|
+
"followupSuggestions",
|
|
19358
|
+
"parallelResponses"
|
|
19303
19359
|
];
|
|
19304
19360
|
|
|
19305
19361
|
// src/helpers/env-checklist.ts
|
|
@@ -19374,7 +19430,8 @@ var FEATURE_DEFAULTS = {
|
|
|
19374
19430
|
mcp: false,
|
|
19375
19431
|
imageGeneration: false,
|
|
19376
19432
|
attachments: false,
|
|
19377
|
-
followupSuggestions: true
|
|
19433
|
+
followupSuggestions: true,
|
|
19434
|
+
parallelResponses: true
|
|
19378
19435
|
};
|
|
19379
19436
|
var AUTH_DEFAULTS = {
|
|
19380
19437
|
google: false,
|
|
@@ -19389,7 +19446,8 @@ var FEATURE_LABELS = {
|
|
|
19389
19446
|
mcp: "MCP Tool Servers",
|
|
19390
19447
|
imageGeneration: "Image Generation",
|
|
19391
19448
|
attachments: "File Attachments",
|
|
19392
|
-
followupSuggestions: "Follow-up Suggestions"
|
|
19449
|
+
followupSuggestions: "Follow-up Suggestions",
|
|
19450
|
+
parallelResponses: "Parallel Responses"
|
|
19393
19451
|
};
|
|
19394
19452
|
var AUTH_LABELS = {
|
|
19395
19453
|
google: "Google OAuth",
|
|
@@ -19514,10 +19572,10 @@ import { dirname, join, resolve } from "node:path";
|
|
|
19514
19572
|
import { fileURLToPath } from "node:url";
|
|
19515
19573
|
|
|
19516
19574
|
// src/utils/run-command.ts
|
|
19517
|
-
import { spawn } from "node:child_process";
|
|
19575
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
19518
19576
|
async function runCommand(command, args, cwd) {
|
|
19519
19577
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
19520
|
-
const child =
|
|
19578
|
+
const child = spawn2(command, args, { cwd, stdio: "pipe" });
|
|
19521
19579
|
const stderr = [];
|
|
19522
19580
|
child.stderr?.on("data", (data) => {
|
|
19523
19581
|
stderr.push(String(data));
|
|
@@ -19552,20 +19610,6 @@ async function scaffoldFromGit(url2, destination) {
|
|
|
19552
19610
|
await rm(join(destination, ".git"), { recursive: true, force: true });
|
|
19553
19611
|
}
|
|
19554
19612
|
|
|
19555
|
-
// src/utils/get-package-manager.ts
|
|
19556
|
-
function inferPackageManager() {
|
|
19557
|
-
const ua = process.env.npm_config_user_agent ?? "";
|
|
19558
|
-
if (ua.startsWith("pnpm/"))
|
|
19559
|
-
return "pnpm";
|
|
19560
|
-
if (ua.startsWith("yarn/"))
|
|
19561
|
-
return "yarn";
|
|
19562
|
-
if (ua.startsWith("npm/"))
|
|
19563
|
-
return "npm";
|
|
19564
|
-
if (ua.startsWith("bun/"))
|
|
19565
|
-
return "bun";
|
|
19566
|
-
return "bun";
|
|
19567
|
-
}
|
|
19568
|
-
|
|
19569
19613
|
// ../../node_modules/ora/index.js
|
|
19570
19614
|
import process10 from "node:process";
|
|
19571
19615
|
|
|
@@ -21056,4 +21100,5 @@ process.on("SIGTERM", () => process.exit(0));
|
|
|
21056
21100
|
var program2 = new Command().name("chat-js").description("ChatJS CLI").version(package_default.version, "-v, --version", "display the version number");
|
|
21057
21101
|
program2.addCommand(create, { isDefault: true });
|
|
21058
21102
|
program2.addCommand(add);
|
|
21103
|
+
program2.addCommand(config2);
|
|
21059
21104
|
program2.parse();
|
package/package.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @chatjs/chat
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#94](https://github.com/FranciscoMoretti/chat-js/pull/94) [`2a8a7cc`](https://github.com/FranciscoMoretti/chat-js/commit/2a8a7cc2b0649bd73e41999dbf0528a21e8065be) Thanks [@FranciscoMoretti](https://github.com/FranciscoMoretti)! - ## Config defaults & `defineConfig` helper
|
|
8
|
+
|
|
9
|
+
### New features
|
|
10
|
+
|
|
11
|
+
- **`defineConfig()` helper** — new type-safe wrapper for `chat.config.ts`. The gateway type is inferred from `ai.gateway`, so autocomplete and type errors are scoped to the model IDs available in the chosen gateway. Replace `satisfies ConfigInput` with `defineConfig({...})`.
|
|
12
|
+
- **Gateway-specific defaults** — all AI config fields (models, tools, workflows) are now optional. Omitted fields are automatically filled from per-gateway defaults at runtime via `applyDefaults()`. Only `ai.gateway` is required.
|
|
13
|
+
- **`chatjs config` CLI command** — new command that prints the fully-resolved configuration for the current project, applying all defaults. Useful for debugging and verifying your setup.
|
|
14
|
+
- **Separate defaults per gateway** — `vercel`, `openrouter`, `openai`, and `openai-compatible` each have their own typed defaults (`ModelDefaultsFor<G>`), ensuring model IDs are validated against the correct gateway's model registry.
|
|
15
|
+
- **Stricter image/video tool schemas** — `tools.image` and `tools.video` now use a discriminated union: `enabled: true` requires a `default` model, while `enabled: false` makes it optional.
|
|
16
|
+
|
|
17
|
+
### Breaking changes
|
|
18
|
+
|
|
19
|
+
None — existing configs using `satisfies ConfigInput` continue to work. Migrating to `defineConfig()` is recommended for better DX but not required.
|
|
@@ -6,13 +6,13 @@ import type { ChatMessage } from "@/lib/ai/types";
|
|
|
6
6
|
import { config } from "@/lib/config";
|
|
7
7
|
|
|
8
8
|
export async function generateTitleFromUserMessage({
|
|
9
|
-
|
|
9
|
+
message,
|
|
10
10
|
}: {
|
|
11
|
-
|
|
11
|
+
message: ChatMessage;
|
|
12
12
|
}) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const { text: title } = await generateText({
|
|
14
|
+
model: await getLanguageModel(config.ai.workflows.title),
|
|
15
|
+
system: `Generate a concise title for a chat conversation based on the user's first message.
|
|
16
16
|
|
|
17
17
|
Rules (strictly follow all):
|
|
18
18
|
- Maximum 40 characters — hard limit, never exceed this
|
|
@@ -21,9 +21,9 @@ Rules (strictly follow all):
|
|
|
21
21
|
- No filler words like "How to" or "Question about"
|
|
22
22
|
- Use title case
|
|
23
23
|
- Return ONLY the title, nothing else`,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
prompt: JSON.stringify(message),
|
|
25
|
+
experimental_telemetry: { isEnabled: true },
|
|
26
|
+
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
return title;
|
|
29
29
|
}
|