ethagent 3.0.1 → 3.1.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/README.md +6 -1
- package/package.json +3 -1
- package/src/app/FirstRun.tsx +1 -24
- package/src/app/firstRunConfig.ts +26 -0
- package/src/auth/openaiOAuth/landingPage.ts +2 -11
- package/src/chat/ChatScreen.tsx +32 -117
- package/src/chat/MessageList.tsx +18 -260
- package/src/chat/chatEnvironment.ts +16 -0
- package/src/chat/chatTurnContext.ts +50 -0
- package/src/chat/chatTurnOrchestrator.ts +5 -112
- package/src/chat/chatTurnRows.ts +64 -0
- package/src/chat/commands.ts +3 -178
- package/src/chat/continuityEditReview.ts +42 -0
- package/src/chat/input/ChatInput.tsx +10 -144
- package/src/chat/input/chatInputHelpers.ts +62 -0
- package/src/chat/input/inputRendering.tsx +93 -0
- package/src/chat/messageMarkdown.ts +220 -0
- package/src/chat/messageRows.ts +43 -0
- package/src/chat/planImplementation.ts +62 -0
- package/src/chat/slashCommandHandlers.ts +165 -0
- package/src/chat/slashCommandViews.ts +120 -0
- package/src/cli/main.tsx +7 -0
- package/src/identity/continuity/challenges.ts +123 -0
- package/src/identity/continuity/envelope.ts +49 -1484
- package/src/identity/continuity/envelopeCreate.ts +322 -0
- package/src/identity/continuity/envelopeCrypto.ts +182 -0
- package/src/identity/continuity/envelopeParse.ts +441 -0
- package/src/identity/continuity/envelopeTypes.ts +204 -0
- package/src/identity/continuity/envelopeVersion.ts +1 -0
- package/src/identity/continuity/payloadNormalization.ts +183 -0
- package/src/identity/continuity/publicSkills.ts +5 -5
- package/src/identity/continuity/skills/loadSkills.ts +12 -69
- package/src/identity/continuity/skills/skillPaths.ts +76 -0
- package/src/identity/continuity/skillsNormalization.ts +119 -0
- package/src/identity/continuity/snapshotToken.ts +28 -0
- package/src/identity/hub/continuity/completion.ts +67 -0
- package/src/identity/hub/continuity/effects.ts +5 -62
- package/src/identity/hub/profile/effects.ts +6 -170
- package/src/identity/hub/profile/operatorSave.ts +202 -0
- package/src/identity/registry/erc8004/metadata.ts +31 -23
- package/src/identity/wallet/browserWallet/html.ts +1 -57
- package/src/identity/wallet/browserWallet/walletPageSource.ts +85 -0
- package/src/identity/wallet/page/controller.ts +1 -1
- package/src/identity/wallet/page/errorView.ts +122 -0
- package/src/identity/wallet/page/view.ts +3 -114
- package/src/mcp/manager.ts +8 -66
- package/src/mcp/managerHelpers.ts +70 -0
- package/src/models/ModelPicker.tsx +69 -889
- package/src/models/huggingface.ts +20 -137
- package/src/models/huggingfaceStorage.ts +136 -0
- package/src/models/llamacpp.ts +37 -303
- package/src/models/llamacppCommands.ts +44 -0
- package/src/models/llamacppConfig.ts +34 -0
- package/src/models/llamacppDiscovery.ts +176 -0
- package/src/models/llamacppOutput.ts +65 -0
- package/src/models/modelPickerCatalogFlow.ts +56 -0
- package/src/models/modelPickerCredentials.ts +166 -0
- package/src/models/modelPickerData.ts +41 -0
- package/src/models/modelPickerDisplay.tsx +132 -0
- package/src/models/modelPickerHfFlow.ts +192 -0
- package/src/models/modelPickerLocalRunnerFlow.ts +115 -0
- package/src/models/modelPickerTypes.ts +69 -0
- package/src/models/modelPickerUninstallFlow.ts +48 -0
- package/src/models/modelPickerViewHelpers.ts +174 -0
- package/src/providers/openai-chat.ts +5 -124
- package/src/providers/openaiChatWire.ts +124 -0
- package/src/runtime/providerTurn.ts +38 -0
- package/src/runtime/textToolParser.ts +161 -0
- package/src/runtime/toolIntent.ts +1 -1
- package/src/runtime/turn.ts +43 -499
- package/src/runtime/turnNudges.ts +223 -0
- package/src/runtime/turnTypes.ts +86 -0
- package/src/ui/terminalTitle.ts +30 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Message, Provider, StreamEvent } from '../providers/contracts.js'
|
|
2
|
+
import type { ProviderTurnEvent } from './turnTypes.js'
|
|
3
|
+
|
|
4
|
+
export async function* runProviderTurn(
|
|
5
|
+
provider: Provider,
|
|
6
|
+
messages: Message[],
|
|
7
|
+
signal: AbortSignal,
|
|
8
|
+
): AsyncIterable<ProviderTurnEvent> {
|
|
9
|
+
if (signal.aborted) {
|
|
10
|
+
yield { type: 'cancelled' }
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
for await (const ev of provider.complete(messages, signal)) {
|
|
14
|
+
if (signal.aborted) {
|
|
15
|
+
yield { type: 'cancelled' }
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
yield normalize(ev)
|
|
19
|
+
if (ev.type === 'done' || ev.type === 'error') return
|
|
20
|
+
}
|
|
21
|
+
if (signal.aborted) {
|
|
22
|
+
yield { type: 'cancelled' }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalize(event: StreamEvent): ProviderTurnEvent {
|
|
27
|
+
switch (event.type) {
|
|
28
|
+
case 'text': return { type: 'text', delta: event.delta }
|
|
29
|
+
case 'thinking': return { type: 'thinking', delta: event.delta }
|
|
30
|
+
case 'thinking_end': return { type: 'thinking_end' }
|
|
31
|
+
case 'retry': return event
|
|
32
|
+
case 'tool_use_start': return event
|
|
33
|
+
case 'tool_use_delta': return event
|
|
34
|
+
case 'tool_use_stop': return event
|
|
35
|
+
case 'done': return { type: 'done', stopReason: event.stopReason }
|
|
36
|
+
case 'error': return { type: 'error', message: event.message }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { Provider } from '../providers/contracts.js'
|
|
2
|
+
import { getTool } from '../tools/registry.js'
|
|
3
|
+
import type { PendingToolUse } from './turnTypes.js'
|
|
4
|
+
|
|
5
|
+
export function parseLocalModelTextToolUse(
|
|
6
|
+
provider: Pick<Provider, 'id'>,
|
|
7
|
+
assistantText: string,
|
|
8
|
+
iterationIndex = 0,
|
|
9
|
+
): PendingToolUse | null {
|
|
10
|
+
const parsed = parseLocalModelTextToolUses(provider, assistantText, iterationIndex)
|
|
11
|
+
return parsed.length === 1 ? parsed[0]! : null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseLocalModelTextToolUses(
|
|
15
|
+
provider: Pick<Provider, 'id'>,
|
|
16
|
+
assistantText: string,
|
|
17
|
+
iterationIndex = 0,
|
|
18
|
+
): PendingToolUse[] {
|
|
19
|
+
if (provider.id !== 'llamacpp') return []
|
|
20
|
+
|
|
21
|
+
const calls = extractTextToolCalls(assistantText)
|
|
22
|
+
if (calls.length === 0) return []
|
|
23
|
+
|
|
24
|
+
return calls.map((call, index) => ({
|
|
25
|
+
id: calls.length === 1 ? `local-text-tool-${iterationIndex}` : `local-text-tool-${iterationIndex}-${index}`,
|
|
26
|
+
name: call.name,
|
|
27
|
+
input: call.input,
|
|
28
|
+
}))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function extractTextToolCalls(text: string): Array<{ name: string; input: Record<string, unknown> }> {
|
|
32
|
+
const payloads = extractToolPayloadCandidates(text)
|
|
33
|
+
const calls = payloads.flatMap(parseTextToolPayloads)
|
|
34
|
+
return calls.filter(call => typeof call.name === 'string' && isRecord(call.input) && Boolean(getTool(call.name)))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function extractToolPayloadCandidates(text: string): string[] {
|
|
38
|
+
const trimmed = text.trim()
|
|
39
|
+
if (!trimmed) return []
|
|
40
|
+
|
|
41
|
+
const exact = normalizeToolPayloadCandidate(trimmed)
|
|
42
|
+
if (exact.startsWith('{') && exact.endsWith('}')) return [exact]
|
|
43
|
+
if (exact.startsWith('[') && exact.endsWith(']')) return [exact]
|
|
44
|
+
|
|
45
|
+
const fencedOnlyMatch = trimmed.match(/^```[^\r\n]*\r?\n([\s\S]*?)\r?\n```$/i)
|
|
46
|
+
if (fencedOnlyMatch) return [normalizeToolPayloadCandidate(fencedOnlyMatch[1]!)]
|
|
47
|
+
|
|
48
|
+
const embedded = [
|
|
49
|
+
...[...trimmed.matchAll(/<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/gi)].map(match => match[1]!),
|
|
50
|
+
...[...trimmed.matchAll(/```[^\r\n]*\r?\n([\s\S]*?)\r?\n```/g)].map(match => match[1]!),
|
|
51
|
+
...extractStandaloneJsonPayloads(trimmed),
|
|
52
|
+
].map(normalizeToolPayloadCandidate)
|
|
53
|
+
|
|
54
|
+
return [...new Set(embedded)]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function extractStandaloneJsonPayloads(text: string): string[] {
|
|
58
|
+
const lines = text.split(/\r?\n/)
|
|
59
|
+
const out: string[] = []
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
62
|
+
const line = lines[i] ?? ''
|
|
63
|
+
const first = normalizeToolPayloadCandidate(line)
|
|
64
|
+
if (!first.startsWith('{') && !first.startsWith('[')) continue
|
|
65
|
+
|
|
66
|
+
let candidate = line
|
|
67
|
+
for (let j = i; j < lines.length; j += 1) {
|
|
68
|
+
if (j > i) candidate += `\n${lines[j] ?? ''}`
|
|
69
|
+
const normalized = normalizeToolPayloadCandidate(candidate)
|
|
70
|
+
if (canParseJson(normalized)) {
|
|
71
|
+
out.push(normalized)
|
|
72
|
+
i = j
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
if (candidate.length > 20_000) break
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return out
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function canParseJson(value: string): boolean {
|
|
83
|
+
try {
|
|
84
|
+
JSON.parse(value)
|
|
85
|
+
return true
|
|
86
|
+
} catch {
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function normalizeToolPayloadCandidate(candidate: string): string {
|
|
92
|
+
let normalized = candidate
|
|
93
|
+
.trim()
|
|
94
|
+
.split(/\r?\n/)
|
|
95
|
+
.map(line => line.replace(/^\s*\d+\s+(?=[{\[<"])/, ''))
|
|
96
|
+
.join('\n')
|
|
97
|
+
.trim()
|
|
98
|
+
|
|
99
|
+
const toolCallMatch = normalized.match(/^<tool_call>\s*([\s\S]*?)\s*<\/tool_call>$/i)
|
|
100
|
+
if (toolCallMatch) normalized = toolCallMatch[1]!.trim()
|
|
101
|
+
return normalized
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function parseTextToolPayloads(payload: string): Array<{ name: string; input: Record<string, unknown> }> {
|
|
105
|
+
let parsed: unknown
|
|
106
|
+
try {
|
|
107
|
+
parsed = JSON.parse(payload)
|
|
108
|
+
} catch {
|
|
109
|
+
return []
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return normalizeParsedToolPayloads(parsed)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function normalizeParsedToolPayloads(value: unknown): Array<{ name: string; input: Record<string, unknown> }> {
|
|
116
|
+
if (Array.isArray(value)) {
|
|
117
|
+
return value.flatMap(normalizeParsedToolPayloads)
|
|
118
|
+
}
|
|
119
|
+
if (!isRecord(value)) return []
|
|
120
|
+
|
|
121
|
+
const toolCalls = value.tool_calls
|
|
122
|
+
if (Array.isArray(toolCalls)) {
|
|
123
|
+
return toolCalls.flatMap(normalizeParsedToolPayloads)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const fn = value.function
|
|
127
|
+
if (isRecord(fn)) {
|
|
128
|
+
const call = normalizeNameAndInput(fn.name, fn.arguments)
|
|
129
|
+
return call ? [call] : []
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const name = value.name ?? value.tool ?? value.tool_name ?? value.function_name
|
|
133
|
+
const rawInput = value.arguments ?? value.input ?? value.parameters ?? value.args ?? {}
|
|
134
|
+
const call = normalizeNameAndInput(name, rawInput)
|
|
135
|
+
return call ? [call] : []
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function normalizeNameAndInput(
|
|
139
|
+
name: unknown,
|
|
140
|
+
rawInput: unknown,
|
|
141
|
+
): { name: string; input: Record<string, unknown> } | null {
|
|
142
|
+
if (typeof name !== 'string') return null
|
|
143
|
+
const input = parseToolInput(rawInput)
|
|
144
|
+
if (!input) return null
|
|
145
|
+
return { name, input }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function parseToolInput(rawInput: unknown): Record<string, unknown> | null {
|
|
149
|
+
if (isRecord(rawInput)) return rawInput
|
|
150
|
+
if (typeof rawInput !== 'string') return null
|
|
151
|
+
try {
|
|
152
|
+
const parsed = JSON.parse(rawInput)
|
|
153
|
+
return isRecord(parsed) ? parsed : null
|
|
154
|
+
} catch {
|
|
155
|
+
return null
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
160
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
161
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PendingToolUse } from './turn.js'
|
|
2
2
|
import { unsupportedToolStateClaims, type ToolEvidence } from './toolClaimGuards.js'
|
|
3
|
-
export { parseLocalModelTextToolUses as extractLocalTextToolUses } from './
|
|
3
|
+
export { parseLocalModelTextToolUses as extractLocalTextToolUses } from './textToolParser.js'
|
|
4
4
|
|
|
5
5
|
export type ToolIntent = {
|
|
6
6
|
name: string
|