@nuvin/nuvin-core 1.1.1 → 1.2.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/VERSION CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.1.1",
3
- "commit": "6744c77"
2
+ "version": "1.2.0",
3
+ "commit": "aafc9e1"
4
4
  }
package/dist/index.d.ts CHANGED
@@ -19,6 +19,11 @@ type AgentTemplate = {
19
19
  shareContext?: boolean;
20
20
  metadata?: Record<string, unknown>;
21
21
  };
22
+ /**
23
+ * CompleteAgent is an AgentTemplate with all required fields populated
24
+ * Used for registered agents that have gone through applyDefaults()
25
+ */
26
+ type CompleteAgent = Required<Pick<AgentTemplate, 'id' | 'name' | 'description' | 'systemPrompt' | 'tools' | 'temperature' | 'maxTokens'>> & Pick<AgentTemplate, 'provider' | 'model' | 'topP' | 'timeoutMs' | 'shareContext' | 'metadata'>;
22
27
  /**
23
28
  * Specialist Agent Configuration (Internal - used by AgentManager)
24
29
  */
@@ -135,7 +140,7 @@ declare class AgentRegistry {
135
140
  */
136
141
  applyDefaults(partial: Partial<AgentTemplate> & {
137
142
  systemPrompt: string;
138
- }): AgentTemplate;
143
+ }): CompleteAgent;
139
144
  /**
140
145
  * Load agents from memory persistence
141
146
  */
@@ -161,7 +166,7 @@ declare class AgentRegistry {
161
166
  /**
162
167
  * Save agent to file
163
168
  */
164
- saveToFile(agent: AgentTemplate): Promise<void>;
169
+ saveToFile(agent: CompleteAgent): Promise<void>;
165
170
  /**
166
171
  * Delete agent from file
167
172
  */
@@ -177,11 +182,11 @@ declare class AgentRegistry {
177
182
  /**
178
183
  * Get an agent template by ID
179
184
  */
180
- get(agentId: string): AgentTemplate | undefined;
185
+ get(agentId: string): CompleteAgent | undefined;
181
186
  /**
182
187
  * List all registered agent templates
183
188
  */
184
- list(): AgentTemplate[];
189
+ list(): CompleteAgent[];
185
190
  /**
186
191
  * Check if an agent exists
187
192
  */
@@ -232,6 +237,7 @@ type ChatMessage = {
232
237
  tool_calls?: ToolCall[];
233
238
  tool_call_id?: string;
234
239
  name?: string;
240
+ [key: string]: unknown;
235
241
  };
236
242
  type CompletionParams = {
237
243
  messages: ChatMessage[];
@@ -259,6 +265,7 @@ type CompletionParams = {
259
265
  usage?: {
260
266
  include?: boolean;
261
267
  };
268
+ [key: string]: unknown;
262
269
  };
263
270
  type UsageData = {
264
271
  prompt_tokens?: number;
@@ -281,6 +288,7 @@ type CompletionResult = {
281
288
  content: string;
282
289
  tool_calls?: ToolCall[];
283
290
  usage?: UsageData;
291
+ [key: string]: unknown;
284
292
  };
285
293
  type Message = {
286
294
  id: string;
@@ -291,6 +299,7 @@ type Message = {
291
299
  tool_call_id?: string;
292
300
  name?: string;
293
301
  usage?: UsageData;
302
+ [key: string]: unknown;
294
303
  };
295
304
  type MessageResponse = {
296
305
  id: string;
@@ -330,6 +339,10 @@ interface LLMPort {
330
339
  onToolCallDelta?: (tc: ToolCall) => void;
331
340
  onStreamFinish?: (finishReason?: string, usage?: UsageData) => void;
332
341
  }, signal?: AbortSignal): Promise<CompletionResult>;
342
+ getModels?(signal?: AbortSignal): Promise<Array<{
343
+ id: string;
344
+ [key: string]: unknown;
345
+ }>>;
333
346
  }
334
347
  type LLMConfig = {
335
348
  provider?: string;
@@ -922,7 +935,7 @@ declare class DefaultSpecialistAgentFactory implements SpecialistAgentFactory {
922
935
  systemContextProvider?: SystemContextProvider;
923
936
  agentListProvider?: AgentListProvider;
924
937
  idGenerator?: IdGenerator;
925
- });
938
+ } | undefined);
926
939
  create(input: SpecialistAgentFactoryInput): SpecialistAgentConfig;
927
940
  }
928
941
 
@@ -938,7 +951,7 @@ declare class AgentManager {
938
951
  private llmResolver;
939
952
  private activeAgents;
940
953
  private eventCollectors;
941
- constructor(delegatingConfig: AgentConfig, delegatingTools: ToolPort, llmFactory?: LLMFactory, eventCallback?: (event: AgentEvent) => void, configResolver?: () => Partial<AgentConfig>);
954
+ constructor(delegatingConfig: AgentConfig, delegatingTools: ToolPort, llmFactory?: LLMFactory | undefined, eventCallback?: ((event: AgentEvent) => void) | undefined, configResolver?: (() => Partial<AgentConfig>) | undefined);
942
955
  /**
943
956
  * Create and execute a specialist agent for a specific task
944
957
  */
@@ -970,7 +983,7 @@ declare class AgentManagerCommandRunner implements AgentCommandRunner {
970
983
  private readonly delegatingTools;
971
984
  private readonly llmFactory?;
972
985
  private readonly configResolver?;
973
- constructor(delegatingConfig: AgentConfig, delegatingTools: ToolPort, llmFactory?: LLMFactory, configResolver?: () => Partial<AgentConfig>);
986
+ constructor(delegatingConfig: AgentConfig, delegatingTools: ToolPort, llmFactory?: LLMFactory | undefined, configResolver?: (() => Partial<AgentConfig>) | undefined);
974
987
  run(config: Parameters<AgentManager['executeTask']>[0], context?: ToolExecutionContext): Promise<SpecialistAgentResult>;
975
988
  }
976
989
 
@@ -995,7 +1008,7 @@ declare class DefaultDelegationResultFormatter implements DelegationResultFormat
995
1008
  status: "success" | "error" | "timeout";
996
1009
  executionTimeMs: number;
997
1010
  toolCallsExecuted: number;
998
- tokensUsed: number;
1011
+ tokensUsed: number | undefined;
999
1012
  };
1000
1013
  };
1001
1014
  formatError(error: unknown): string;
@@ -1157,9 +1170,9 @@ declare class GithubAuthTransport implements HttpTransport {
1157
1170
  }
1158
1171
 
1159
1172
  declare class LLMError extends Error {
1160
- readonly statusCode?: number;
1173
+ readonly statusCode?: number | undefined;
1161
1174
  readonly isRetryable: boolean;
1162
- constructor(message: string, statusCode?: number, isRetryable?: boolean, cause?: unknown);
1175
+ constructor(message: string, statusCode?: number | undefined, isRetryable?: boolean, cause?: unknown);
1163
1176
  }
1164
1177
  declare abstract class BaseLLM implements LLMPort {
1165
1178
  protected transport: HttpTransport | null;
@@ -1169,7 +1182,7 @@ declare abstract class BaseLLM implements LLMPort {
1169
1182
  enablePromptCaching?: boolean;
1170
1183
  });
1171
1184
  protected abstract createTransport(): HttpTransport;
1172
- private getTransport;
1185
+ protected getTransport(): HttpTransport;
1173
1186
  protected applyCacheControl(params: CompletionParams): CompletionParams;
1174
1187
  generateCompletion(params: CompletionParams, signal?: AbortSignal): Promise<CompletionResult>;
1175
1188
  streamCompletion(params: CompletionParams, handlers?: {
@@ -1185,10 +1198,32 @@ type GithubOptions = {
1185
1198
  apiUrl?: string;
1186
1199
  httpLogFile?: string;
1187
1200
  };
1201
+ type GithubModel = {
1202
+ id: string;
1203
+ name: string;
1204
+ capable_endpoints?: string[];
1205
+ supported_endpoints?: string[];
1206
+ capabilities: {
1207
+ family: string;
1208
+ type: string;
1209
+ limits?: {
1210
+ max_context_window_tokens?: number;
1211
+ max_output_tokens?: number;
1212
+ };
1213
+ };
1214
+ };
1188
1215
  declare class GithubLLM extends BaseLLM implements LLMPort {
1189
1216
  private readonly opts;
1190
1217
  constructor(opts?: GithubOptions);
1191
1218
  protected createTransport(): GithubAuthTransport;
1219
+ getModels(signal?: AbortSignal): Promise<GithubModel[]>;
1220
+ private handleError;
1221
+ generateCompletion(params: CompletionParams, signal?: AbortSignal): Promise<CompletionResult>;
1222
+ streamCompletion(params: CompletionParams, handlers?: {
1223
+ onChunk?: (delta: string, usage?: UsageData) => void;
1224
+ onToolCallDelta?: (tc: ToolCall) => void;
1225
+ onStreamFinish?: (finishReason?: string, usage?: UsageData) => void;
1226
+ }, signal?: AbortSignal): Promise<CompletionResult>;
1192
1227
  }
1193
1228
 
1194
1229
  type AnthropicAISDKOptions = {
@@ -1328,6 +1363,7 @@ declare function loadMCPConfig(filePath?: string): Promise<MCPConfig | null>;
1328
1363
  declare class PersistingConsoleEventPort implements EventPort {
1329
1364
  private memory;
1330
1365
  private maxPerConversation;
1366
+ private writeQueue;
1331
1367
  constructor(opts?: {
1332
1368
  memory?: MemoryPort<AgentEvent>;
1333
1369
  filename?: string;
@@ -1342,4 +1378,4 @@ declare function resolveBackspaces(s: string): string;
1342
1378
  declare function stripAnsiAndControls(s: string): string;
1343
1379
  declare function canonicalizeTerminalPaste(raw: string): string;
1344
1380
 
1345
- export { AGENT_CREATOR_SYSTEM_PROMPT, type AgentAwareToolPort, type AgentCatalog, type AgentConfig, type AgentEvent, AgentEventTypes, AgentFilePersistence, AgentManager, AgentManagerCommandRunner, AgentOrchestrator, AgentRegistry, type AgentTemplate, AnthropicAISDKLLM, type AssignParams, BashTool, CompositeToolPort, type Conversation, ConversationContext, type ConversationMetadata, type ConversationSnapshot, ConversationStore, CoreMCPClient, DefaultDelegationPolicy, DefaultDelegationResultFormatter, DefaultDelegationService, DefaultSpecialistAgentFactory, type DelegationService, type DelegationServiceConfig, DelegationServiceFactory, ErrorReason, type FolderTreeOptions, GithubLLM, InMemoryMemory, InMemoryMetadata, JsonFileMemoryPersistence, type LLMConfig, LLMError, type LLMFactory, type LLMOptions, type LLMPort, LLMResolver, type MCPConfig, type MCPServerConfig, MCPToolPort, type MemoryPort, MemoryPortMetadataAdapter, type Message, type MessageContent, type MessageContentPart, type MetadataPort, NoopReminders, type OrchestratorAwareToolPort, PersistedMemory, PersistingConsoleEventPort, RuntimeEnv, type SendMessageOptions, SimpleContextBuilder, SimpleCost, SimpleId, type SpecialistAgentConfig, type SpecialistAgentResult, SystemClock, type ToolApprovalDecision, type ToolCall, type ToolExecutionResult, type ToolPort, ToolRegistry, type UserAttachment, type UserMessagePayload, buildAgentCreationPrompt, buildInjectedSystem, canonicalizeTerminalPaste, createLLM, generateFolderTree, getAvailableProviders, loadMCPConfig, normalizeNewlines, renderTemplate, resolveBackspaces, resolveCarriageReturns, stripAnsiAndControls, supportsGetModels };
1381
+ export { AGENT_CREATOR_SYSTEM_PROMPT, type AgentAwareToolPort, type AgentCatalog, type AgentConfig, type AgentEvent, AgentEventTypes, AgentFilePersistence, AgentManager, AgentManagerCommandRunner, AgentOrchestrator, AgentRegistry, type AgentTemplate, AnthropicAISDKLLM, type AssignParams, BashTool, type CompleteAgent, CompositeToolPort, type Conversation, ConversationContext, type ConversationMetadata, type ConversationSnapshot, ConversationStore, CoreMCPClient, DefaultDelegationPolicy, DefaultDelegationResultFormatter, DefaultDelegationService, DefaultSpecialistAgentFactory, type DelegationService, type DelegationServiceConfig, DelegationServiceFactory, ErrorReason, type FolderTreeOptions, GithubLLM, InMemoryMemory, InMemoryMetadata, JsonFileMemoryPersistence, type LLMConfig, LLMError, type LLMFactory, type LLMOptions, type LLMPort, LLMResolver, type MCPConfig, type MCPServerConfig, MCPToolPort, type MemoryPort, MemoryPortMetadataAdapter, type Message, type MessageContent, type MessageContentPart, type MetadataPort, NoopReminders, type OrchestratorAwareToolPort, PersistedMemory, PersistingConsoleEventPort, RuntimeEnv, type SendMessageOptions, SimpleContextBuilder, SimpleCost, SimpleId, type SpecialistAgentConfig, type SpecialistAgentResult, SystemClock, type ToolApprovalDecision, type ToolCall, type ToolExecutionResult, type ToolPort, ToolRegistry, type UserAttachment, type UserMessagePayload, buildAgentCreationPrompt, buildInjectedSystem, canonicalizeTerminalPaste, createLLM, generateFolderTree, getAvailableProviders, loadMCPConfig, normalizeNewlines, renderTemplate, resolveBackspaces, resolveCarriageReturns, stripAnsiAndControls, supportsGetModels };
package/dist/index.js CHANGED
@@ -450,7 +450,13 @@ var AgentOrchestrator = class {
450
450
  });
451
451
  }
452
452
  await this.deps.memory.append(convo, [assistantMsg, ...toolResultMsgs]);
453
- accumulatedMessages.push({ role: "assistant", content: result.content ?? null, tool_calls: approvedCalls });
453
+ const { usage: _usage, ...extraField } = result;
454
+ accumulatedMessages.push({
455
+ ...extraField,
456
+ role: "assistant",
457
+ content: result.content ?? null,
458
+ tool_calls: approvedCalls
459
+ });
454
460
  for (const tr of toolResults) {
455
461
  const contentStr = tr.status === "error" ? String(tr.result) : typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result);
456
462
  accumulatedMessages.push({ role: "tool", content: contentStr, tool_call_id: tr.id, name: tr.name });
@@ -638,9 +644,18 @@ var SimpleContextBuilder = class {
638
644
  transformed.push({ role: "user", content: providerContent ?? "" });
639
645
  } else if (m.role === "assistant") {
640
646
  if (m.tool_calls && m.tool_calls.length > 0) {
641
- transformed.push({ role: "assistant", content: providerContent ?? null, tool_calls: m.tool_calls });
647
+ transformed.push({
648
+ ...m,
649
+ role: "assistant",
650
+ content: providerContent ?? null,
651
+ tool_calls: m.tool_calls
652
+ });
642
653
  } else {
643
- transformed.push({ role: "assistant", content: providerContent ?? "" });
654
+ transformed.push({
655
+ ...m,
656
+ role: "assistant",
657
+ content: providerContent ?? ""
658
+ });
644
659
  }
645
660
  } else if (m.role === "tool") {
646
661
  if (m.tool_call_id) {
@@ -2384,8 +2399,12 @@ var BashTool = class {
2384
2399
  }
2385
2400
  arr.push(chunk);
2386
2401
  };
2387
- child.stdout.on("data", (d) => capPush(stdout, d));
2388
- child.stderr.on("data", (d) => capPush(stderr, d));
2402
+ if (child.stdout) {
2403
+ child.stdout.on("data", (d) => capPush(stdout, d));
2404
+ }
2405
+ if (child.stderr) {
2406
+ child.stderr.on("data", (d) => capPush(stderr, d));
2407
+ }
2389
2408
  const exit = new Promise((res) => {
2390
2409
  child.on("close", (code, signal2) => res({ code, signal: signal2 }));
2391
2410
  });
@@ -2643,8 +2662,10 @@ var AgentRegistry = class {
2643
2662
  this.filePersistence = options?.filePersistence;
2644
2663
  for (const agent of defaultAgents) {
2645
2664
  const complete = this.applyDefaults(agent);
2646
- this.agents.set(complete.id, complete);
2647
- this.defaultAgentIds.add(complete.id);
2665
+ if (complete.id) {
2666
+ this.agents.set(complete.id, complete);
2667
+ this.defaultAgentIds.add(complete.id);
2668
+ }
2648
2669
  }
2649
2670
  this.loadingPromise = this.loadAgents();
2650
2671
  }
@@ -2726,7 +2747,7 @@ var AgentRegistry = class {
2726
2747
  for (const agent of loadedAgents) {
2727
2748
  if (this.validateTemplate(agent)) {
2728
2749
  const complete = this.applyDefaults(agent);
2729
- if (!this.defaultAgentIds.has(complete.id)) {
2750
+ if (complete.id && !this.defaultAgentIds.has(complete.id)) {
2730
2751
  this.agents.set(complete.id, complete);
2731
2752
  }
2732
2753
  }
@@ -2775,9 +2796,6 @@ var AgentRegistry = class {
2775
2796
  if (!this.filePersistence) {
2776
2797
  throw new Error("File persistence not configured");
2777
2798
  }
2778
- if (!agent.id) {
2779
- throw new Error("Cannot save agent without ID");
2780
- }
2781
2799
  if (this.defaultAgentIds.has(agent.id)) {
2782
2800
  throw new Error(`Cannot save default agent "${agent.id}" to file`);
2783
2801
  }
@@ -2999,8 +3017,8 @@ var AgentManager = class {
2999
3017
  this.llmFactory = llmFactory;
3000
3018
  this.eventCallback = eventCallback;
3001
3019
  this.configResolver = configResolver;
3002
- if (llmFactory) {
3003
- this.llmResolver = new LLMResolver(llmFactory);
3020
+ if (this.llmFactory) {
3021
+ this.llmResolver = new LLMResolver(this.llmFactory);
3004
3022
  }
3005
3023
  }
3006
3024
  llmResolver = null;
@@ -3178,7 +3196,9 @@ var AgentManager = class {
3178
3196
  */
3179
3197
  resolveLLM(config) {
3180
3198
  if (!this.llmResolver) {
3181
- throw new Error("AgentManager requires LLMFactory to create sub-agents. Please provide llmFactory in constructor.");
3199
+ throw new Error(
3200
+ "AgentManager requires LLMFactory to create sub-agents. Please provide llmFactory in constructor."
3201
+ );
3182
3202
  }
3183
3203
  return this.llmResolver.resolve(config);
3184
3204
  }
@@ -3411,9 +3431,7 @@ var ToolRegistry = class {
3411
3431
  const delegationService = factory.create({
3412
3432
  agentRegistry: this.agentRegistry,
3413
3433
  commandRunner,
3414
- agentListProvider: () => this.agentRegistry.list().filter(
3415
- (agent) => typeof agent.id === "string" && typeof agent.name === "string" && typeof agent.description === "string"
3416
- ).map((agent) => ({
3434
+ agentListProvider: () => this.agentRegistry.list().map((agent) => ({
3417
3435
  id: agent.id,
3418
3436
  name: agent.name,
3419
3437
  description: agent.description
@@ -3685,9 +3703,7 @@ var AgentFilePersistence = class {
3685
3703
  fs8.unlinkSync(filePath);
3686
3704
  }
3687
3705
  } catch (error) {
3688
- throw new Error(
3689
- `Failed to delete agent ${agentId}: ${error instanceof Error ? error.message : String(error)}`
3690
- );
3706
+ throw new Error(`Failed to delete agent ${agentId}: ${error instanceof Error ? error.message : String(error)}`);
3691
3707
  }
3692
3708
  }
3693
3709
  /**
@@ -3716,6 +3732,7 @@ var AgentFilePersistence = class {
3716
3732
  function mergeChoices(choices) {
3717
3733
  const contentParts = [];
3718
3734
  const mergedToolCalls = [];
3735
+ const extraFields = {};
3719
3736
  const collectText = (value) => {
3720
3737
  if (typeof value === "string") {
3721
3738
  const trimmed = value.trim();
@@ -3736,10 +3753,20 @@ function mergeChoices(choices) {
3736
3753
  if (!msg) continue;
3737
3754
  collectText(msg.content);
3738
3755
  if (Array.isArray(msg.tool_calls)) mergedToolCalls.push(...msg.tool_calls);
3756
+ const knownKeys = ["content", "tool_calls", "role"];
3757
+ for (const key of Object.keys(msg)) {
3758
+ if (!knownKeys.includes(key)) {
3759
+ extraFields[key] = msg[key];
3760
+ }
3761
+ }
3739
3762
  }
3740
3763
  const content = contentParts.join("\n\n");
3741
3764
  const tool_calls = mergedToolCalls.length ? mergedToolCalls : void 0;
3742
- return { content, ...tool_calls ? { tool_calls } : {} };
3765
+ return {
3766
+ content,
3767
+ ...tool_calls ? { tool_calls } : {},
3768
+ ...extraFields
3769
+ };
3743
3770
  }
3744
3771
  function normalizeUsage(usage) {
3745
3772
  if (!usage) return void 0;
@@ -3900,6 +3927,7 @@ var BaseLLM = class {
3900
3927
  const mergedToolCalls = [];
3901
3928
  let usage;
3902
3929
  let lastFinishReason;
3930
+ const extraFields = {};
3903
3931
  const flushEvent = (rawEvent) => {
3904
3932
  const lines = rawEvent.split("\n");
3905
3933
  const dataLines = [];
@@ -3927,7 +3955,7 @@ var BaseLLM = class {
3927
3955
  }
3928
3956
  for (const ch of choices) {
3929
3957
  const delta = ch.delta ?? ch.message ?? {};
3930
- const textDelta = delta.content || delta.reasoning;
3958
+ const textDelta = delta.content ?? void 0;
3931
3959
  if (typeof textDelta === "string" && textDelta.length > 0) {
3932
3960
  if (content === "") {
3933
3961
  const trimmedDelta = textDelta.replace(/^\n+/, "");
@@ -3940,6 +3968,16 @@ var BaseLLM = class {
3940
3968
  handlers.onChunk?.(textDelta);
3941
3969
  }
3942
3970
  }
3971
+ const knownKeys = ["role", "content", "tool_calls"];
3972
+ for (const key of Object.keys(delta)) {
3973
+ if (knownKeys.includes(key)) continue;
3974
+ const val = delta[key];
3975
+ if (typeof val === "string") {
3976
+ extraFields[key] = (extraFields[key] || "") + val;
3977
+ } else if (val !== void 0 && val !== null) {
3978
+ extraFields[key] = val;
3979
+ }
3980
+ }
3943
3981
  const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
3944
3982
  for (const td of toolDeltas) {
3945
3983
  let toolCall;
@@ -3947,6 +3985,7 @@ var BaseLLM = class {
3947
3985
  toolCall = mergedToolCalls.find((tc) => tc.id === td.id);
3948
3986
  if (!toolCall) {
3949
3987
  toolCall = {
3988
+ ...td,
3950
3989
  id: td.id,
3951
3990
  type: "function",
3952
3991
  function: { name: td.function?.name ?? "", arguments: "" }
@@ -3993,7 +4032,12 @@ var BaseLLM = class {
3993
4032
  if (buffer.trim()) flushEvent(buffer);
3994
4033
  content = content.replace(/^\n+/, "");
3995
4034
  const tool_calls = mergedToolCalls.length ? mergedToolCalls : void 0;
3996
- return { content, ...tool_calls ? { tool_calls } : {}, ...usage ? { usage } : {} };
4035
+ return {
4036
+ content,
4037
+ ...tool_calls ? { tool_calls } : {},
4038
+ ...usage ? { usage } : {},
4039
+ ...extraFields
4040
+ };
3997
4041
  }
3998
4042
  };
3999
4043
 
@@ -4363,8 +4407,9 @@ var GithubAuthTransport = class {
4363
4407
  method: "GET",
4364
4408
  headers: {
4365
4409
  Authorization: `Bearer ${this.accessToken}`,
4366
- "user-agent": "GitHubCopilotChat/0.31.3",
4367
- "editor-version": "vscode/1.104.2",
4410
+ "user-agent": "GitHubCopilotChat/0.33.1",
4411
+ "editor-version": "vscode/1.106.1",
4412
+ "x-github-api-version": "2025-10-01",
4368
4413
  accept: "application/json"
4369
4414
  },
4370
4415
  signal
@@ -4393,7 +4438,7 @@ var GithubAuthTransport = class {
4393
4438
  if (!Array.isArray(messages.messages)) return false;
4394
4439
  return messages.messages.some((msg) => isVisionMessage(msg));
4395
4440
  }
4396
- makeAuthHeaders(url, headers, body) {
4441
+ makeAuthHeaders(headers, body) {
4397
4442
  const base = headers ? { ...headers } : {};
4398
4443
  if (this.apiKey) base.Authorization = `Bearer ${this.apiKey}`;
4399
4444
  base["editor-version"] = base["editor-version"] || "vscode/1.104.2";
@@ -4431,11 +4476,11 @@ var GithubAuthTransport = class {
4431
4476
  await this.exchangeToken(signal);
4432
4477
  }
4433
4478
  const fullUrl = this.buildFullUrl(url);
4434
- let res = await this.inner.get(fullUrl, this.makeAuthHeaders(fullUrl, headers), signal);
4479
+ let res = await this.inner.get(fullUrl, this.makeAuthHeaders(headers), signal);
4435
4480
  if (res.status === 401 && this.accessToken) {
4436
4481
  await this.exchangeToken(signal);
4437
4482
  const retryUrl = this.buildFullUrl(url);
4438
- res = await this.inner.get(retryUrl, this.makeAuthHeaders(retryUrl, headers), signal);
4483
+ res = await this.inner.get(retryUrl, this.makeAuthHeaders(headers), signal);
4439
4484
  }
4440
4485
  return res;
4441
4486
  }
@@ -4444,25 +4489,26 @@ var GithubAuthTransport = class {
4444
4489
  await this.exchangeToken(signal);
4445
4490
  }
4446
4491
  const fullUrl = this.buildFullUrl(url);
4447
- let res = await this.inner.postJson(fullUrl, body, this.makeAuthHeaders(fullUrl, headers, body), signal);
4492
+ let res = await this.inner.postJson(fullUrl, body, this.makeAuthHeaders(headers, body), signal);
4448
4493
  if (res.status === 401 && this.accessToken) {
4449
4494
  await this.exchangeToken(signal);
4450
4495
  const retryUrl = this.buildFullUrl(url);
4451
- res = await this.inner.postJson(retryUrl, body, this.makeAuthHeaders(retryUrl, headers, body), signal);
4496
+ res = await this.inner.postJson(retryUrl, body, this.makeAuthHeaders(headers, body), signal);
4452
4497
  }
4453
4498
  return res;
4454
4499
  }
4455
4500
  async postStream(url, body, headers, signal) {
4456
- if (!this.apiKey && this.accessToken) {
4501
+ let hdrs = this.makeAuthHeaders({ Accept: "text/event-stream", ...headers || {} }, body);
4502
+ if ((!this.apiKey || !hdrs.Authorization) && this.accessToken) {
4457
4503
  await this.exchangeToken(signal);
4504
+ hdrs = this.makeAuthHeaders({ Accept: "text/event-stream", ...headers || {} }, body);
4458
4505
  }
4459
4506
  const fullUrl = this.buildFullUrl(url);
4460
- const hdrs = this.makeAuthHeaders(fullUrl, { Accept: "text/event-stream", ...headers || {} }, body);
4461
4507
  let res = await this.inner.postStream(fullUrl, body, hdrs, signal);
4462
4508
  if (res.status === 401 && this.accessToken) {
4463
4509
  await this.exchangeToken(signal);
4464
4510
  const retryUrl = this.buildFullUrl(url);
4465
- res = await this.inner.postStream(retryUrl, body, this.makeAuthHeaders(retryUrl, hdrs, body), signal);
4511
+ res = await this.inner.postStream(retryUrl, body, this.makeAuthHeaders(hdrs, body), signal);
4466
4512
  }
4467
4513
  return res;
4468
4514
  }
@@ -4551,6 +4597,49 @@ var GithubLLM = class extends BaseLLM {
4551
4597
  accessToken: this.opts.accessToken
4552
4598
  });
4553
4599
  }
4600
+ async getModels(signal) {
4601
+ const res = await this.getTransport().get("/models", void 0, signal);
4602
+ if (!res.ok) {
4603
+ const text = await res.text();
4604
+ throw new LLMError(text || `Failed to fetch models: ${res.status}`, res.status);
4605
+ }
4606
+ const body = await res.json();
4607
+ return body.data;
4608
+ }
4609
+ handleError(error, model) {
4610
+ if (error instanceof LLMError) {
4611
+ try {
4612
+ const errorBody = JSON.parse(error.message);
4613
+ if (errorBody?.error?.code === "unsupported_api_for_model") {
4614
+ throw new LLMError(
4615
+ `The model '${model}' is not supported for chat completions. Please select a different model using '/model'.`,
4616
+ error.statusCode,
4617
+ false
4618
+ // Not retryable
4619
+ );
4620
+ }
4621
+ } catch (e) {
4622
+ if (e instanceof LLMError && e.message.includes("not supported")) {
4623
+ throw e;
4624
+ }
4625
+ }
4626
+ }
4627
+ throw error;
4628
+ }
4629
+ async generateCompletion(params, signal) {
4630
+ try {
4631
+ return await super.generateCompletion(params, signal);
4632
+ } catch (error) {
4633
+ this.handleError(error, params.model);
4634
+ }
4635
+ }
4636
+ async streamCompletion(params, handlers, signal) {
4637
+ try {
4638
+ return await super.streamCompletion(params, handlers, signal);
4639
+ } catch (error) {
4640
+ this.handleError(error, params.model);
4641
+ }
4642
+ }
4554
4643
  };
4555
4644
 
4556
4645
  // llm-providers/llm-anthropic-aisdk.ts
@@ -4601,9 +4690,11 @@ var AnthropicAISDKLLM = class {
4601
4690
  }
4602
4691
  updateCredentials(result) {
4603
4692
  if (result.type === "success" && result.access && result.refresh && result.expires) {
4604
- this.opts.oauth.access = result.access;
4605
- this.opts.oauth.refresh = result.refresh;
4606
- this.opts.oauth.expires = result.expires;
4693
+ if (this.opts.oauth) {
4694
+ this.opts.oauth.access = result.access;
4695
+ this.opts.oauth.refresh = result.refresh;
4696
+ this.opts.oauth.expires = result.expires;
4697
+ }
4607
4698
  this.opts.onTokenUpdate?.({
4608
4699
  access: result.access,
4609
4700
  refresh: result.refresh,
@@ -5405,7 +5496,7 @@ function normalizeMCPConfig(raw) {
5405
5496
  return { mcpServers: servers };
5406
5497
  }
5407
5498
  }
5408
- if (asRecord.config && typeof asRecord.config === "object") {
5499
+ if ("config" in asRecord && asRecord.config && typeof asRecord.config === "object") {
5409
5500
  const nested = asRecord.config;
5410
5501
  if (isValidConfig(nested)) {
5411
5502
  const servers = nested.mcpServers;
@@ -5434,23 +5525,26 @@ function isValidConfig(value) {
5434
5525
 
5435
5526
  // events.ts
5436
5527
  var PersistingConsoleEventPort = class {
5437
- // private console = new ConsoleEventPort();
5438
5528
  memory;
5439
5529
  maxPerConversation;
5530
+ writeQueue = Promise.resolve();
5440
5531
  constructor(opts) {
5441
5532
  this.memory = opts?.memory ?? new PersistedMemory(new JsonFileMemoryPersistence(opts?.filename || "events.json"));
5442
5533
  this.maxPerConversation = opts?.maxPerConversation ?? 500;
5443
5534
  }
5444
5535
  async emit(event) {
5445
- try {
5446
- const key = event?.conversationId ?? "default";
5447
- const existing = await this.memory.get(key);
5448
- const next = [...existing, { ...event }];
5449
- const max = this.maxPerConversation;
5450
- const trimmed = max > 0 && next.length > max ? next.slice(next.length - max) : next;
5451
- await this.memory.set(key, trimmed);
5452
- } catch {
5453
- }
5536
+ this.writeQueue = this.writeQueue.then(async () => {
5537
+ try {
5538
+ const key = event?.conversationId ?? "default";
5539
+ const existing = await this.memory.get(key);
5540
+ const next = [...existing, { ...event }];
5541
+ const max = this.maxPerConversation;
5542
+ const trimmed = max > 0 && next.length > max ? next.slice(next.length - max) : next;
5543
+ await this.memory.set(key, trimmed);
5544
+ } catch {
5545
+ }
5546
+ });
5547
+ return this.writeQueue;
5454
5548
  }
5455
5549
  };
5456
5550
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuvin/nuvin-core",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "private": false,
6
6
  "main": "dist/index.js",