novacode 0.5.2 → 0.5.3

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/src/util.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isAbsolute, relative } from "node:path"
2
2
  import chalk from "chalk"
3
- import type { ContentPart, Msg, TextPart } from "./types.ts"
3
+ import type { Msg, TextPart } from "./types.ts"
4
4
 
5
5
  // ~4 chars per token for English/code. Close enough for capacity warnings.
6
6
  export function estimateTokens(messages: Msg[]): number {
@@ -21,33 +21,6 @@ export function textPart(s: string): TextPart {
21
21
  return { type: "text", text: s }
22
22
  }
23
23
 
24
- export function consolidate(parts: ContentPart[]): ContentPart[] {
25
- if (parts.length === 0) return parts
26
- const out: ContentPart[] = []
27
- for (const p of parts) {
28
- const last = out[out.length - 1]
29
- if (last?.type === "text" && p.type === "text") {
30
- last.text += p.text
31
- } else if (last?.type === "thinking" && p.type === "thinking") {
32
- last.text += p.text
33
- } else {
34
- out.push({ ...p })
35
- }
36
- }
37
-
38
- const hasTool = out.some((p) => p.type === "tool_call")
39
- if (hasTool) {
40
- return out.filter((p) => {
41
- if (p.type === "text") {
42
- return p.text.trim().length > 0
43
- }
44
- return true
45
- })
46
- }
47
-
48
- return out
49
- }
50
-
51
24
  export function getRelativeIfInside(cwd: string, filePath: string): string {
52
25
  if (filePath === cwd || filePath.startsWith(`${cwd}/`)) {
53
26
  return relative(cwd, filePath) || "."
@@ -1,62 +0,0 @@
1
- /**
2
- * Registry for different model providers (OpenAI, Anthropic, etc.).
3
- * Provides a unified streaming interface for the agent loop.
4
- */
5
- import type { AgentEvent, ApiFormat, AssistantResult, StreamFn, StreamOpts } from "../types.ts"
6
- import { EventStream } from "./stream.ts"
7
-
8
- export type { AssistantResult, StreamEvent, StreamFn, StreamOpts } from "../types.ts"
9
-
10
- // Internal map of registered provider implementations
11
- const registry = new Map<ApiFormat, StreamFn>()
12
-
13
- export function register(api: ApiFormat, fn: StreamFn): void {
14
- registry.set(api, fn)
15
- }
16
-
17
- // Bridges provider-specific StreamEvents into AgentEvents so the loop and TUI deal with one type.
18
- export function stream(opts: StreamOpts): EventStream<AgentEvent, AssistantResult> {
19
- const fn = registry.get(opts.api)
20
- if (!fn) throw new Error(`No provider registered for API format: ${opts.api}`)
21
-
22
- // Bridge layer: converts provider-specific StreamEvents into the agent's
23
- // AgentEvent shape, so the loop and TUI only deal with one event type.
24
- const providerStream = fn(opts)
25
- const agentStream = new EventStream<AgentEvent, AssistantResult>()
26
-
27
- ;(async () => {
28
- for await (const event of providerStream) {
29
- if (event.type === "text_delta") {
30
- agentStream.push({ type: "text_delta", text: event.text ?? "" })
31
- } else if (event.type === "thinking_delta") {
32
- agentStream.push({ type: "thinking_delta", text: event.text ?? "" })
33
- } else if (event.type === "tool_call" && event.call) {
34
- agentStream.push({
35
- type: "tool_call",
36
- call: {
37
- type: "tool_call",
38
- id: event.call.id,
39
- name: event.call.name,
40
- args: event.call.args,
41
- },
42
- })
43
- } else if (event.type === "usage" && event.usage) {
44
- agentStream.push({ type: "usage", usage: event.usage })
45
- }
46
- }
47
-
48
- const res = providerStream.result
49
- if (res) {
50
- agentStream.finish(res)
51
- } else {
52
- // Fallback for unexpected closure
53
- agentStream.finish({ content: [], usage: { in: 0, out: 0 }, stop: "stop" })
54
- }
55
- })()
56
-
57
- return agentStream
58
- }
59
-
60
- export function getRegisteredApis(): ApiFormat[] {
61
- return [...registry.keys()]
62
- }