@agentex/agent 0.0.23 → 0.0.26
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/CHANGELOG.md +338 -0
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/derived.d.ts +5 -3
- package/dist/derived.d.ts.map +1 -1
- package/dist/derived.js +11 -7
- package/dist/derived.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/acp/index.d.ts +1 -1
- package/dist/providers/acp/index.d.ts.map +1 -1
- package/dist/providers/acp/index.js +5 -97
- package/dist/providers/acp/index.js.map +1 -1
- package/dist/providers/acp/session.d.ts +8 -1
- package/dist/providers/acp/session.d.ts.map +1 -1
- package/dist/providers/acp/session.js +94 -0
- package/dist/providers/acp/session.js.map +1 -1
- package/dist/providers/claude/attach.d.ts +8 -0
- package/dist/providers/claude/attach.d.ts.map +1 -0
- package/dist/providers/claude/attach.js +113 -0
- package/dist/providers/claude/attach.js.map +1 -0
- package/dist/providers/claude/execute.d.ts.map +1 -1
- package/dist/providers/claude/execute.js +17 -2
- package/dist/providers/claude/execute.js.map +1 -1
- package/dist/providers/claude/goal-capability.d.ts +15 -0
- package/dist/providers/claude/goal-capability.d.ts.map +1 -0
- package/dist/providers/claude/goal-capability.js +20 -0
- package/dist/providers/claude/goal-capability.js.map +1 -0
- package/dist/providers/claude/index.d.ts.map +1 -1
- package/dist/providers/claude/index.js +8 -4
- package/dist/providers/claude/index.js.map +1 -1
- package/dist/providers/claude/session.d.ts +11 -9
- package/dist/providers/claude/session.d.ts.map +1 -1
- package/dist/providers/claude/session.js +36 -14
- package/dist/providers/claude/session.js.map +1 -1
- package/dist/providers/codex/attach.d.ts +9 -0
- package/dist/providers/codex/attach.d.ts.map +1 -0
- package/dist/providers/codex/attach.js +93 -0
- package/dist/providers/codex/attach.js.map +1 -0
- package/dist/providers/codex/execute.d.ts.map +1 -1
- package/dist/providers/codex/execute.js +17 -3
- package/dist/providers/codex/execute.js.map +1 -1
- package/dist/providers/codex/goal-capability.d.ts +13 -0
- package/dist/providers/codex/goal-capability.d.ts.map +1 -0
- package/dist/providers/codex/goal-capability.js +18 -0
- package/dist/providers/codex/goal-capability.js.map +1 -0
- package/dist/providers/codex/index.d.ts +1 -0
- package/dist/providers/codex/index.d.ts.map +1 -1
- package/dist/providers/codex/index.js +9 -6
- package/dist/providers/codex/index.js.map +1 -1
- package/dist/providers/codex/session.d.ts +11 -7
- package/dist/providers/codex/session.d.ts.map +1 -1
- package/dist/providers/codex/session.js +37 -12
- package/dist/providers/codex/session.js.map +1 -1
- package/dist/providers/codex/transcript-normalize.d.ts +28 -0
- package/dist/providers/codex/transcript-normalize.d.ts.map +1 -0
- package/dist/providers/codex/transcript-normalize.js +191 -0
- package/dist/providers/codex/transcript-normalize.js.map +1 -0
- package/dist/providers/cursor/index.d.ts.map +1 -1
- package/dist/providers/cursor/index.js +2 -2
- package/dist/providers/cursor/index.js.map +1 -1
- package/dist/providers/openclaw/index.d.ts.map +1 -1
- package/dist/providers/openclaw/index.js +2 -2
- package/dist/providers/openclaw/index.js.map +1 -1
- package/dist/providers/opencode/index.d.ts.map +1 -1
- package/dist/providers/opencode/index.js +3 -5
- package/dist/providers/opencode/index.js.map +1 -1
- package/dist/providers/pi/index.d.ts.map +1 -1
- package/dist/providers/pi/index.js +3 -5
- package/dist/providers/pi/index.js.map +1 -1
- package/dist/providers/process/index.d.ts.map +1 -1
- package/dist/providers/process/index.js +2 -2
- package/dist/providers/process/index.js.map +1 -1
- package/dist/registry.d.ts +0 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +0 -4
- package/dist/registry.js.map +1 -1
- package/dist/sessions/index.d.ts +3 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +2 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/record.d.ts +43 -0
- package/dist/sessions/record.d.ts.map +1 -0
- package/dist/sessions/record.js +85 -0
- package/dist/sessions/record.js.map +1 -0
- package/dist/types.d.ts +176 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/endpoint.d.ts +38 -0
- package/dist/utils/endpoint.d.ts.map +1 -0
- package/dist/utils/endpoint.js +151 -0
- package/dist/utils/endpoint.js.map +1 -0
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +5 -1
- package/dist/utils/env.js.map +1 -1
- package/dist/utils/uuid.d.ts +7 -1
- package/dist/utils/uuid.d.ts.map +1 -1
- package/dist/utils/uuid.js +21 -1
- package/dist/utils/uuid.js.map +1 -1
- package/package.json +64 -7
- package/src/derived.ts +311 -0
- package/src/goals/controller.ts +442 -0
- package/src/goals/index.ts +21 -0
- package/src/goals/normalize.ts +173 -0
- package/src/goals/sentinel.ts +90 -0
- package/src/index.ts +270 -0
- package/src/providers/_shared/http-agent.ts +304 -0
- package/src/providers/acp/index.ts +103 -0
- package/src/providers/acp/parse.ts +131 -0
- package/src/providers/acp/session.ts +744 -0
- package/src/providers/claude/attach.ts +147 -0
- package/src/providers/claude/codec.ts +43 -0
- package/src/providers/claude/execute.ts +300 -0
- package/src/providers/claude/goal-capability.ts +21 -0
- package/src/providers/claude/index.ts +72 -0
- package/src/providers/claude/mcp.ts +82 -0
- package/src/providers/claude/parse.ts +824 -0
- package/src/providers/claude/session.ts +1192 -0
- package/src/providers/claude/transcript.ts +555 -0
- package/src/providers/codex/attach.ts +123 -0
- package/src/providers/codex/codec.ts +50 -0
- package/src/providers/codex/execute.ts +337 -0
- package/src/providers/codex/goal-capability.ts +19 -0
- package/src/providers/codex/index.ts +57 -0
- package/src/providers/codex/modes.ts +159 -0
- package/src/providers/codex/parse.ts +691 -0
- package/src/providers/codex/plan-mode.ts +49 -0
- package/src/providers/codex/session.ts +1287 -0
- package/src/providers/codex/transcript-normalize.ts +197 -0
- package/src/providers/codex/transcript.ts +487 -0
- package/src/providers/codex/usage-scanner.ts +178 -0
- package/src/providers/copilot/index.ts +19 -0
- package/src/providers/cursor/codec.ts +44 -0
- package/src/providers/cursor/execute.ts +271 -0
- package/src/providers/cursor/index.ts +25 -0
- package/src/providers/cursor/parse.ts +288 -0
- package/src/providers/gemini/index.ts +21 -0
- package/src/providers/openclaw/codec.ts +40 -0
- package/src/providers/openclaw/execute.ts +19 -0
- package/src/providers/openclaw/index.ts +29 -0
- package/src/providers/opencode/codec.ts +50 -0
- package/src/providers/opencode/event-parse.ts +141 -0
- package/src/providers/opencode/execute.ts +251 -0
- package/src/providers/opencode/http-session.ts +427 -0
- package/src/providers/opencode/index.ts +30 -0
- package/src/providers/opencode/parse.ts +203 -0
- package/src/providers/opencode/server.ts +0 -0
- package/src/providers/pi/codec.ts +44 -0
- package/src/providers/pi/execute.ts +297 -0
- package/src/providers/pi/index.ts +30 -0
- package/src/providers/pi/parse.ts +231 -0
- package/src/providers/pi/session.ts +381 -0
- package/src/providers/process/execute.ts +148 -0
- package/src/providers/process/index.ts +52 -0
- package/src/registry.ts +40 -0
- package/src/sessions/index.ts +8 -0
- package/src/sessions/record.ts +108 -0
- package/src/types.ts +1638 -0
- package/src/utils/ask-user-question.ts +57 -0
- package/src/utils/auth.ts +661 -0
- package/src/utils/binary.ts +179 -0
- package/src/utils/endpoint.ts +172 -0
- package/src/utils/env.ts +63 -0
- package/src/utils/execute-all.ts +68 -0
- package/src/utils/exit-plan-mode.ts +40 -0
- package/src/utils/instructions.ts +427 -0
- package/src/utils/process.ts +223 -0
- package/src/utils/runtime-config.ts +100 -0
- package/src/utils/runtime-homes.ts +49 -0
- package/src/utils/skill-commands.ts +493 -0
- package/src/utils/skills.ts +500 -0
- package/src/utils/template.ts +16 -0
- package/src/utils/tool-names.ts +51 -0
- package/src/utils/uuid.ts +21 -0
- package/src/utils/workspace.ts +156 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GoalSentinel,
|
|
3
|
+
GoalSentinelContext,
|
|
4
|
+
GoalSentinelVerdict,
|
|
5
|
+
TurnResult,
|
|
6
|
+
} from "../types.js";
|
|
7
|
+
|
|
8
|
+
/** Normalize a sentinel's `boolean | {met,nudge}` return into a verdict. */
|
|
9
|
+
export async function runSentinel(
|
|
10
|
+
sentinel: GoalSentinel,
|
|
11
|
+
ctx: GoalSentinelContext,
|
|
12
|
+
): Promise<GoalSentinelVerdict> {
|
|
13
|
+
const out = await sentinel(ctx);
|
|
14
|
+
if (typeof out === "boolean") return { met: out };
|
|
15
|
+
return { met: out.met === true, ...(out.nudge ? { nudge: out.nudge } : {}) };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The objective doubles as the first turn's directive (matching native `/goal`,
|
|
20
|
+
* which starts a turn immediately with the condition). Kept verbatim so a goal
|
|
21
|
+
* like "All tests pass under `pnpm test`" reads naturally as a task.
|
|
22
|
+
*/
|
|
23
|
+
export function buildKickoffMessage(objective: string): string {
|
|
24
|
+
return objective;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Continuation message sent when the sentinel judges the goal not-yet-met. */
|
|
28
|
+
export function defaultNudge(objective: string, iterations: number): string {
|
|
29
|
+
return [
|
|
30
|
+
`The goal is not yet satisfied (attempt ${iterations + 1}). Keep working until it is fully met, then stop.`,
|
|
31
|
+
"",
|
|
32
|
+
"Goal:",
|
|
33
|
+
objective,
|
|
34
|
+
].join("\n");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Prompt for the default sentinel's self-assessment turn. The model must answer
|
|
39
|
+
* with a single leading token so the parse is unambiguous.
|
|
40
|
+
*/
|
|
41
|
+
export function buildAssessmentPrompt(objective: string): string {
|
|
42
|
+
return [
|
|
43
|
+
"Assess ONLY whether the goal below is now fully and verifiably met by the work done so far in this conversation.",
|
|
44
|
+
"Answer with exactly one word on the first line: YES if it is fully met, otherwise NO.",
|
|
45
|
+
"Do not perform any further work; do not edit files. Just judge.",
|
|
46
|
+
"",
|
|
47
|
+
"Goal:",
|
|
48
|
+
objective,
|
|
49
|
+
].join("\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parse a yes/no self-assessment answer. Conservative: only an explicit
|
|
54
|
+
* affirmative ("yes"/"met"/"complete"/"done"/"satisfied" as the first token, or
|
|
55
|
+
* a clear standalone "YES") counts as met. Anything ambiguous → not met, so the
|
|
56
|
+
* loop keeps working rather than declaring premature success.
|
|
57
|
+
*/
|
|
58
|
+
export function parseAssessment(text: string): boolean {
|
|
59
|
+
const trimmed = text.trim().toLowerCase();
|
|
60
|
+
if (!trimmed) return false;
|
|
61
|
+
const firstToken = (trimmed.split(/[\s,.:!]+/)[0] ?? "").replace(/[^a-z]/g, "");
|
|
62
|
+
if (["no", "not", "incomplete", "unmet", "false"].includes(firstToken)) return false;
|
|
63
|
+
if (["yes", "met", "complete", "completed", "done", "satisfied", "true"].includes(firstToken)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
// Fall back to a strict scan for an unambiguous affirmative phrase.
|
|
67
|
+
return /\b(goal\s+is\s+)?(fully\s+)?(met|complete|completed|satisfied)\b/.test(trimmed)
|
|
68
|
+
&& !/\bnot\b/.test(trimmed);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build the library's default sentinel: ask the running provider to self-assess
|
|
73
|
+
* whether the goal is met. Borrows Claude's design (judge from what the working
|
|
74
|
+
* model surfaced) but uses the same session — so it adds a meta-turn to the
|
|
75
|
+
* transcript. NOTE: the meta-turn runs with the session's normal tool/permission
|
|
76
|
+
* grant; the prompt ASKS the model not to act, but that is not enforced, so this
|
|
77
|
+
* is not a true read-only judge. Hosts with a deterministic check (e.g. run
|
|
78
|
+
* tests) should pass their own `sentinel`; this is the of-last-resort default.
|
|
79
|
+
*
|
|
80
|
+
* `metaSend` runs a turn and resolves with its TurnResult. The controller wires
|
|
81
|
+
* it so the meta-turn's own settle is ignored by the goal loop (no recursion).
|
|
82
|
+
*/
|
|
83
|
+
export function createDefaultSentinel(deps: {
|
|
84
|
+
metaSend: (message: string) => Promise<TurnResult>;
|
|
85
|
+
}): GoalSentinel {
|
|
86
|
+
return async (ctx: GoalSentinelContext): Promise<GoalSentinelVerdict> => {
|
|
87
|
+
const turn = await deps.metaSend(buildAssessmentPrompt(ctx.objective));
|
|
88
|
+
return { met: parseAssessment(turn.summary ?? "") };
|
|
89
|
+
};
|
|
90
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Functions
|
|
2
|
+
export { getProvider, listProviders, registerProvider } from "./registry.js";
|
|
3
|
+
export {
|
|
4
|
+
defineDerivedProvider,
|
|
5
|
+
loadProvidersFromConfig,
|
|
6
|
+
registerAcpFactory,
|
|
7
|
+
MalformedProviderConfigError,
|
|
8
|
+
} from "./derived.js";
|
|
9
|
+
export type { DerivedProviderConfig, AcpFactory } from "./derived.js";
|
|
10
|
+
export { acpProvider } from "./providers/acp/index.js";
|
|
11
|
+
export type { AcpProviderConfig } from "./providers/acp/index.js";
|
|
12
|
+
export type { AcpTransformers } from "./providers/acp/session.js";
|
|
13
|
+
export {
|
|
14
|
+
runHttpAgent,
|
|
15
|
+
httpAgentProvider,
|
|
16
|
+
httpAgentSessionCodec,
|
|
17
|
+
} from "./providers/_shared/http-agent.js";
|
|
18
|
+
export type { HttpAgentOptions } from "./providers/_shared/http-agent.js";
|
|
19
|
+
export { renderTemplate } from "./utils/template.js";
|
|
20
|
+
export { redactEnvForLogs } from "./utils/env.js";
|
|
21
|
+
export {
|
|
22
|
+
translateEndpoint,
|
|
23
|
+
CODEX_CUSTOM_PROVIDER_ID,
|
|
24
|
+
CODEX_CUSTOM_KEY_ENV,
|
|
25
|
+
} from "./utils/endpoint.js";
|
|
26
|
+
export type { EndpointTranslation } from "./utils/endpoint.js";
|
|
27
|
+
export { parseAskUserQuestion } from "./utils/ask-user-question.js";
|
|
28
|
+
export { parseExitPlanMode } from "./utils/exit-plan-mode.js";
|
|
29
|
+
export { aggregateUsage } from "./types.js";
|
|
30
|
+
export {
|
|
31
|
+
resolveInstructions,
|
|
32
|
+
installInstructions,
|
|
33
|
+
removeInstructions,
|
|
34
|
+
resolveInstructionTargets,
|
|
35
|
+
upsertManagedBlock,
|
|
36
|
+
stripManagedBlock,
|
|
37
|
+
} from "./utils/instructions.js";
|
|
38
|
+
export type {
|
|
39
|
+
InstallInstructionsOptions,
|
|
40
|
+
InstructionStatus,
|
|
41
|
+
InstructionInstallEntry,
|
|
42
|
+
InstructionInstallResult,
|
|
43
|
+
InstructionTarget,
|
|
44
|
+
RemoveInstructionsOptions,
|
|
45
|
+
InstructionRemoveStatus,
|
|
46
|
+
InstructionRemoveEntry,
|
|
47
|
+
InstructionRemoveResult,
|
|
48
|
+
ManagedBlockOptions,
|
|
49
|
+
} from "./utils/instructions.js";
|
|
50
|
+
export { getRuntimeHomeEnvVar, getDefaultRuntimeHome } from "./utils/runtime-homes.js";
|
|
51
|
+
export { findBinary, ensureCommandResolvable, clearBinaryCache } from "./utils/binary.js";
|
|
52
|
+
export type { ResolvedBinary } from "./utils/binary.js";
|
|
53
|
+
export {
|
|
54
|
+
detectAuth,
|
|
55
|
+
resolveAuthForProvider,
|
|
56
|
+
clearAuthCache,
|
|
57
|
+
hasSubscription,
|
|
58
|
+
hasApiKey,
|
|
59
|
+
hasBedrock,
|
|
60
|
+
isLoggedIn,
|
|
61
|
+
loginCommandFor,
|
|
62
|
+
} from "./utils/auth.js";
|
|
63
|
+
export type { ResolvedAuth } from "./utils/auth.js";
|
|
64
|
+
export { prepareWorkspace } from "./utils/workspace.js";
|
|
65
|
+
export type { WorkspaceOptions, PreparedWorkspace, DiffOptions } from "./utils/workspace.js";
|
|
66
|
+
export { withTempConfig } from "./utils/runtime-config.js";
|
|
67
|
+
export type { TempConfigResult, TempConfigOptions } from "./utils/runtime-config.js";
|
|
68
|
+
export { executeAll } from "./utils/execute-all.js";
|
|
69
|
+
export type { ExecuteAllOptions, ExecuteAllTask } from "./utils/execute-all.js";
|
|
70
|
+
export {
|
|
71
|
+
getClaudeUnknownDetails,
|
|
72
|
+
getClaudeTaskDetails,
|
|
73
|
+
classifyClaudeAuthFromResult,
|
|
74
|
+
CLAUDE_LOGIN_COMMAND,
|
|
75
|
+
} from "./providers/claude/parse.js";
|
|
76
|
+
export type {
|
|
77
|
+
ClaudeTaskDetails,
|
|
78
|
+
ClaudeTaskUsage,
|
|
79
|
+
ClaudeTaskStatus,
|
|
80
|
+
} from "./providers/claude/parse.js";
|
|
81
|
+
export {
|
|
82
|
+
getClaudeTranscriptPath,
|
|
83
|
+
findClaudeTranscriptBySessionId,
|
|
84
|
+
readClaudeTranscript,
|
|
85
|
+
peekClaudeTranscript,
|
|
86
|
+
claudeTranscriptOps,
|
|
87
|
+
sanitizeProjectPath,
|
|
88
|
+
resolveClaudeHome,
|
|
89
|
+
canonicalizeCwd,
|
|
90
|
+
MAX_SANITIZED_LENGTH,
|
|
91
|
+
} from "./providers/claude/transcript.js";
|
|
92
|
+
export type {
|
|
93
|
+
GetClaudeTranscriptPathOptions,
|
|
94
|
+
ClaudeTranscriptLocation,
|
|
95
|
+
FindClaudeTranscriptOptions,
|
|
96
|
+
FoundClaudeTranscript,
|
|
97
|
+
ReadClaudeTranscriptOptions,
|
|
98
|
+
ClaudeTranscriptYield,
|
|
99
|
+
ClaudePeekResult,
|
|
100
|
+
} from "./providers/claude/transcript.js";
|
|
101
|
+
export {
|
|
102
|
+
getCodexTranscriptPath,
|
|
103
|
+
readCodexTranscript,
|
|
104
|
+
peekCodexTranscript,
|
|
105
|
+
readCodexCwd,
|
|
106
|
+
codexTranscriptOps,
|
|
107
|
+
parseCodexLine,
|
|
108
|
+
resolveCodexHome,
|
|
109
|
+
} from "./providers/codex/transcript.js";
|
|
110
|
+
export { codexLineToStreamEvents } from "./providers/codex/transcript-normalize.js";
|
|
111
|
+
export type {
|
|
112
|
+
GetCodexTranscriptPathOptions,
|
|
113
|
+
CodexTranscriptLocation,
|
|
114
|
+
ReadCodexTranscriptOptions,
|
|
115
|
+
CodexTranscriptYield,
|
|
116
|
+
CodexTranscriptLine,
|
|
117
|
+
CodexPeekResult,
|
|
118
|
+
} from "./providers/codex/transcript.js";
|
|
119
|
+
|
|
120
|
+
// Skills
|
|
121
|
+
export {
|
|
122
|
+
installSkills,
|
|
123
|
+
removeSkills,
|
|
124
|
+
listInstalledSkills,
|
|
125
|
+
resolveSkillsHome,
|
|
126
|
+
resolveSkillsWorkspace,
|
|
127
|
+
resolveNativeSkillsHome,
|
|
128
|
+
resolveNativeSkillsWorkspace,
|
|
129
|
+
ensureSkillSymlink,
|
|
130
|
+
} from "./utils/skills.js";
|
|
131
|
+
export {
|
|
132
|
+
commandInventoryFromEvent,
|
|
133
|
+
discoverSkillCommands,
|
|
134
|
+
reconcileSkillCommands,
|
|
135
|
+
formatSlashInvocation,
|
|
136
|
+
invokeSkill,
|
|
137
|
+
buildExpandedSkillPrompt,
|
|
138
|
+
} from "./utils/skill-commands.js";
|
|
139
|
+
|
|
140
|
+
// Types
|
|
141
|
+
export type {
|
|
142
|
+
ProviderModule,
|
|
143
|
+
ProviderCapabilities,
|
|
144
|
+
AgentMode,
|
|
145
|
+
ListModesOptions,
|
|
146
|
+
ExecutionContext,
|
|
147
|
+
ExecutionResult,
|
|
148
|
+
ExecutionStatus,
|
|
149
|
+
ProviderConfig,
|
|
150
|
+
ProviderEndpointConfig,
|
|
151
|
+
McpServerConfig,
|
|
152
|
+
StreamEvent,
|
|
153
|
+
SessionCodec,
|
|
154
|
+
SessionState,
|
|
155
|
+
TokenUsage,
|
|
156
|
+
ModelUsage,
|
|
157
|
+
RateLimitInfo,
|
|
158
|
+
BaseStreamEventFields,
|
|
159
|
+
LifecycleEvent,
|
|
160
|
+
QuotaStatus,
|
|
161
|
+
QuotaContext,
|
|
162
|
+
AuthMethod,
|
|
163
|
+
AuthSource,
|
|
164
|
+
AuthOption,
|
|
165
|
+
AuthReport,
|
|
166
|
+
AuthResolveContext,
|
|
167
|
+
AuthIdentity,
|
|
168
|
+
AuthRequiredReason,
|
|
169
|
+
BinaryStatus,
|
|
170
|
+
ProviderModel,
|
|
171
|
+
SessionContext,
|
|
172
|
+
AgentSession,
|
|
173
|
+
SendHandle,
|
|
174
|
+
SendOptions,
|
|
175
|
+
CancelResult,
|
|
176
|
+
StopTaskResult,
|
|
177
|
+
TurnResult,
|
|
178
|
+
UserInputRequest,
|
|
179
|
+
UserInputResponse,
|
|
180
|
+
ElicitationRequest,
|
|
181
|
+
ElicitationResponse,
|
|
182
|
+
HookCallbackRequest,
|
|
183
|
+
HookCallbackResponse,
|
|
184
|
+
TranscriptOps,
|
|
185
|
+
TranscriptYield,
|
|
186
|
+
TranscriptPeek,
|
|
187
|
+
FoundTranscript,
|
|
188
|
+
GoalStatus,
|
|
189
|
+
GoalBlockedReason,
|
|
190
|
+
GoalSource,
|
|
191
|
+
GoalCapability,
|
|
192
|
+
GoalState,
|
|
193
|
+
GoalOptions,
|
|
194
|
+
SetGoalResult,
|
|
195
|
+
ClearGoalResult,
|
|
196
|
+
GoalSentinel,
|
|
197
|
+
GoalSentinelVerdict,
|
|
198
|
+
GoalSentinelContext,
|
|
199
|
+
} from "./types.js";
|
|
200
|
+
|
|
201
|
+
// Goals
|
|
202
|
+
export {
|
|
203
|
+
GoalController,
|
|
204
|
+
EMULATED_GOAL_CAPABILITY,
|
|
205
|
+
GOAL_OBJECTIVE_MAX,
|
|
206
|
+
CODEX_GOAL_TOOLS,
|
|
207
|
+
isTerminalGoalStatus,
|
|
208
|
+
goalStateFromEvent,
|
|
209
|
+
latestGoalFromEvents,
|
|
210
|
+
normalizeClaudeGoalAttachment,
|
|
211
|
+
normalizeCodexGoalStatus,
|
|
212
|
+
normalizeCodexGoalRecord,
|
|
213
|
+
createDefaultSentinel,
|
|
214
|
+
parseAssessment,
|
|
215
|
+
} from "./goals/index.js";
|
|
216
|
+
export type {
|
|
217
|
+
GoalControllerDeps,
|
|
218
|
+
GoalStatusEvent,
|
|
219
|
+
NormalizedGoalFields,
|
|
220
|
+
} from "./goals/index.js";
|
|
221
|
+
|
|
222
|
+
// Durable sessions
|
|
223
|
+
export {
|
|
224
|
+
SESSION_RECORD_VERSION,
|
|
225
|
+
MalformedSessionRecordError,
|
|
226
|
+
createSessionRecord,
|
|
227
|
+
isSessionRecord,
|
|
228
|
+
assertSessionRecord,
|
|
229
|
+
} from "./sessions/index.js";
|
|
230
|
+
export type { CreateSessionRecordInput } from "./sessions/index.js";
|
|
231
|
+
export type {
|
|
232
|
+
SessionRecord,
|
|
233
|
+
LastTurnStatus,
|
|
234
|
+
CatchUpYield,
|
|
235
|
+
CatchUpOptions,
|
|
236
|
+
AttachOptions,
|
|
237
|
+
SessionAttachment,
|
|
238
|
+
} from "./types.js";
|
|
239
|
+
|
|
240
|
+
export type {
|
|
241
|
+
AskUserQuestion,
|
|
242
|
+
QuestionOption,
|
|
243
|
+
} from "./utils/ask-user-question.js";
|
|
244
|
+
|
|
245
|
+
export type { ExitPlanModeRequest } from "./utils/exit-plan-mode.js";
|
|
246
|
+
|
|
247
|
+
export type {
|
|
248
|
+
SkillRuntime,
|
|
249
|
+
SkillLocation,
|
|
250
|
+
SkillChannel,
|
|
251
|
+
InstallSkillsOptions,
|
|
252
|
+
SkillInstallEntry,
|
|
253
|
+
SkillInstallResult,
|
|
254
|
+
RemoveSkillsOptions,
|
|
255
|
+
SkillRemoveEntry,
|
|
256
|
+
SkillRemoveResult,
|
|
257
|
+
InstalledSkill,
|
|
258
|
+
} from "./utils/skills.js";
|
|
259
|
+
|
|
260
|
+
export type {
|
|
261
|
+
SkillCommandSource,
|
|
262
|
+
SkillCommandExecution,
|
|
263
|
+
SkillCommandDescriptor,
|
|
264
|
+
RuntimeCommandInventory,
|
|
265
|
+
SkillCommandDiagnostic,
|
|
266
|
+
DiscoverSkillCommandsOptions,
|
|
267
|
+
DiscoverSkillCommandsResult,
|
|
268
|
+
ReconcileSkillCommandsOptions,
|
|
269
|
+
InvokeSkillOptions,
|
|
270
|
+
} from "./utils/skill-commands.js";
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthReport,
|
|
3
|
+
ExecutionContext,
|
|
4
|
+
ExecutionResult,
|
|
5
|
+
ProviderModule,
|
|
6
|
+
SessionCodec,
|
|
7
|
+
} from "../../types.js";
|
|
8
|
+
import { uuidv7 } from "../../utils/uuid.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reusable "remote HTTP agent" adapter — the pattern OpenClaw encodes and the
|
|
12
|
+
* shape any gateway-backed agent reuses: resolve a gateway URL (per-call command
|
|
13
|
+
* override → saved sessionParams → default), round-trip a session key through
|
|
14
|
+
* `sessionParams`, POST the prompt, map 401/403 to an `auth_required` event, and
|
|
15
|
+
* bound the request with an AbortController timeout.
|
|
16
|
+
*/
|
|
17
|
+
export interface HttpAgentOptions {
|
|
18
|
+
/** Provider id (used on events + the result). */
|
|
19
|
+
providerType: string;
|
|
20
|
+
/** Gateway base URL used when neither `config.command` nor a saved URL is set. */
|
|
21
|
+
defaultBaseUrl: string;
|
|
22
|
+
/** Path appended to the base URL for the run endpoint (e.g. "/api/agent/run"). */
|
|
23
|
+
runPath: string;
|
|
24
|
+
/** Recovery command surfaced on `auth_required` (e.g. "openclaw login"). */
|
|
25
|
+
loginCommand?: string;
|
|
26
|
+
/** Build the JSON request body. Default: `{ prompt, sessionKey?, model? }`. */
|
|
27
|
+
buildBody?: (input: { prompt: string; sessionKey: string | null; model: string | null }) => Record<string, unknown>;
|
|
28
|
+
/** Pull the summary text from the gateway response. Default: summary ?? result ?? output. */
|
|
29
|
+
extractSummary?: (response: Record<string, unknown>) => string | null;
|
|
30
|
+
/** Pull the (possibly new) session key from the response. Default: `response.sessionKey ?? prev`. */
|
|
31
|
+
extractSessionKey?: (response: Record<string, unknown>, prev: string | null) => string | null;
|
|
32
|
+
/** Pull the model id from the response. Default: `response.model ?? fallback`. */
|
|
33
|
+
extractModel?: (response: Record<string, unknown>, fallback: string | null) => string | null;
|
|
34
|
+
/** Pull the cost from the response. Default: `response.costUsd` when numeric. */
|
|
35
|
+
extractCost?: (response: Record<string, unknown>) => number | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function str(v: unknown): string | null {
|
|
39
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function defaultSummary(r: Record<string, unknown>): string | null {
|
|
43
|
+
return str(r["summary"]) ?? str(r["result"]) ?? str(r["output"]);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Resolve the session key from session params (sessionKey / session_key). */
|
|
47
|
+
function readSessionKey(sessionParams: Record<string, unknown> | null | undefined): string | null {
|
|
48
|
+
if (!sessionParams) return null;
|
|
49
|
+
return str(sessionParams["sessionKey"]) ?? str(sessionParams["session_key"]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Execute a single turn against a remote HTTP agent gateway. */
|
|
53
|
+
export async function runHttpAgent(
|
|
54
|
+
opts: HttpAgentOptions,
|
|
55
|
+
ctx: ExecutionContext,
|
|
56
|
+
): Promise<ExecutionResult> {
|
|
57
|
+
const runId = ctx.runId ?? uuidv7();
|
|
58
|
+
const model = ctx.model ?? ctx.config?.model ?? null;
|
|
59
|
+
const config = ctx.config ?? {};
|
|
60
|
+
const startedAt = new Date().toISOString();
|
|
61
|
+
const startMs = Date.now();
|
|
62
|
+
|
|
63
|
+
const savedGatewayUrl = str(ctx.sessionParams?.["gatewayUrl"]);
|
|
64
|
+
const gatewayUrl = config.command?.trim() || savedGatewayUrl || opts.defaultBaseUrl;
|
|
65
|
+
const endpoint = gatewayUrl.replace(/\/$/, "") + opts.runPath;
|
|
66
|
+
|
|
67
|
+
const sessionKey = readSessionKey(ctx.sessionParams);
|
|
68
|
+
const body = opts.buildBody
|
|
69
|
+
? opts.buildBody({ prompt: ctx.prompt, sessionKey, model })
|
|
70
|
+
: {
|
|
71
|
+
prompt: ctx.prompt,
|
|
72
|
+
...(sessionKey ? { sessionKey } : {}),
|
|
73
|
+
...(model ? { model } : {}),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const abortController = new AbortController();
|
|
77
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | null = null;
|
|
78
|
+
let timedOut = false;
|
|
79
|
+
if (config.timeoutSec && config.timeoutSec > 0) {
|
|
80
|
+
timeoutHandle = setTimeout(() => {
|
|
81
|
+
timedOut = true;
|
|
82
|
+
abortController.abort();
|
|
83
|
+
}, config.timeoutSec * 1000);
|
|
84
|
+
}
|
|
85
|
+
// Chain a caller-supplied signal (a caller abort is distinct from a timeout).
|
|
86
|
+
if (ctx.signal) {
|
|
87
|
+
if (ctx.signal.aborted) abortController.abort();
|
|
88
|
+
else ctx.signal.addEventListener("abort", () => abortController.abort(), { once: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch(endpoint, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: { "Content-Type": "application/json" },
|
|
95
|
+
body: JSON.stringify(body),
|
|
96
|
+
signal: abortController.signal,
|
|
97
|
+
});
|
|
98
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
99
|
+
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
const errorText = await response.text().catch(() => "");
|
|
102
|
+
const isAuth = response.status === 401 || response.status === 403;
|
|
103
|
+
if (isAuth && ctx.onEvent) {
|
|
104
|
+
try {
|
|
105
|
+
await ctx.onEvent({
|
|
106
|
+
type: "auth_required",
|
|
107
|
+
httpStatus: response.status,
|
|
108
|
+
reason: "unknown",
|
|
109
|
+
loginCommand: opts.loginCommand ?? `${opts.providerType} login`,
|
|
110
|
+
message: errorText || null,
|
|
111
|
+
timestamp: new Date().toISOString(),
|
|
112
|
+
providerType: opts.providerType,
|
|
113
|
+
sessionId: sessionKey ?? null,
|
|
114
|
+
messageId: null,
|
|
115
|
+
eventId: null,
|
|
116
|
+
turnId: null,
|
|
117
|
+
parentToolCallId: null,
|
|
118
|
+
raw: { status: response.status, body: errorText },
|
|
119
|
+
});
|
|
120
|
+
} catch {
|
|
121
|
+
/* swallow */
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
runId,
|
|
126
|
+
exitCode: 1,
|
|
127
|
+
signal: null,
|
|
128
|
+
status: "failed",
|
|
129
|
+
startedAt,
|
|
130
|
+
completedAt: new Date().toISOString(),
|
|
131
|
+
durationMs: Date.now() - startMs,
|
|
132
|
+
errorMessage: `${opts.providerType} gateway returned ${response.status}: ${errorText}`,
|
|
133
|
+
errorCode: isAuth ? "auth_required" : null,
|
|
134
|
+
costUsd: null,
|
|
135
|
+
model,
|
|
136
|
+
summary: null,
|
|
137
|
+
sessionParams: sessionKey ? { sessionKey, gatewayUrl } : null,
|
|
138
|
+
sessionDisplayId: sessionKey,
|
|
139
|
+
clearSession: false,
|
|
140
|
+
billingType: null,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = (await response.json()) as Record<string, unknown>;
|
|
145
|
+
const newSessionKey = opts.extractSessionKey
|
|
146
|
+
? opts.extractSessionKey(result, sessionKey)
|
|
147
|
+
: (str(result["sessionKey"]) ?? sessionKey);
|
|
148
|
+
const summary = (opts.extractSummary ?? defaultSummary)(result);
|
|
149
|
+
const resolvedModel = opts.extractModel
|
|
150
|
+
? opts.extractModel(result, model)
|
|
151
|
+
: (str(result["model"]) ?? model);
|
|
152
|
+
const costUsd = opts.extractCost
|
|
153
|
+
? opts.extractCost(result)
|
|
154
|
+
: typeof result["costUsd"] === "number"
|
|
155
|
+
? (result["costUsd"] as number)
|
|
156
|
+
: null;
|
|
157
|
+
|
|
158
|
+
if (ctx.onEvent && summary) {
|
|
159
|
+
try {
|
|
160
|
+
await ctx.onEvent({
|
|
161
|
+
type: "result",
|
|
162
|
+
text: summary,
|
|
163
|
+
costUsd,
|
|
164
|
+
isError: false,
|
|
165
|
+
stopReason: null,
|
|
166
|
+
terminalReason: null,
|
|
167
|
+
numTurns: null,
|
|
168
|
+
durationMs: null,
|
|
169
|
+
timestamp: new Date().toISOString(),
|
|
170
|
+
providerType: opts.providerType,
|
|
171
|
+
sessionId: newSessionKey ?? null,
|
|
172
|
+
messageId: null,
|
|
173
|
+
eventId: null,
|
|
174
|
+
turnId: null,
|
|
175
|
+
parentToolCallId: null,
|
|
176
|
+
raw: result,
|
|
177
|
+
});
|
|
178
|
+
} catch {
|
|
179
|
+
/* swallow */
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
runId,
|
|
185
|
+
exitCode: 0,
|
|
186
|
+
signal: null,
|
|
187
|
+
status: "completed",
|
|
188
|
+
startedAt,
|
|
189
|
+
completedAt: new Date().toISOString(),
|
|
190
|
+
durationMs: Date.now() - startMs,
|
|
191
|
+
errorMessage: null,
|
|
192
|
+
errorCode: null,
|
|
193
|
+
costUsd,
|
|
194
|
+
model: resolvedModel,
|
|
195
|
+
summary,
|
|
196
|
+
sessionParams: newSessionKey ? { sessionKey: newSessionKey, gatewayUrl } : null,
|
|
197
|
+
sessionDisplayId: newSessionKey,
|
|
198
|
+
clearSession: false,
|
|
199
|
+
billingType: null,
|
|
200
|
+
raw: result,
|
|
201
|
+
};
|
|
202
|
+
} catch (err) {
|
|
203
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
204
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
205
|
+
// A timeout and a caller-supplied signal abort both surface as AbortError;
|
|
206
|
+
// distinguish them so consumers can tell a deadline from a cancellation.
|
|
207
|
+
const isTimeout = timedOut;
|
|
208
|
+
return {
|
|
209
|
+
runId,
|
|
210
|
+
exitCode: null,
|
|
211
|
+
signal: null,
|
|
212
|
+
status: isTimeout ? "timeout" : "aborted",
|
|
213
|
+
startedAt,
|
|
214
|
+
completedAt: new Date().toISOString(),
|
|
215
|
+
durationMs: Date.now() - startMs,
|
|
216
|
+
errorMessage: isTimeout ? `Timed out after ${config.timeoutSec ?? 0}s` : "Aborted by caller",
|
|
217
|
+
errorCode: isTimeout ? "timeout" : "aborted",
|
|
218
|
+
costUsd: null,
|
|
219
|
+
model,
|
|
220
|
+
summary: null,
|
|
221
|
+
sessionParams: sessionKey ? { sessionKey, gatewayUrl } : null,
|
|
222
|
+
sessionDisplayId: sessionKey,
|
|
223
|
+
clearSession: false,
|
|
224
|
+
billingType: null,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// A transient network error (DNS, reset) is recoverable — preserve the
|
|
228
|
+
// session key / gateway so the caller can resume rather than losing it.
|
|
229
|
+
return {
|
|
230
|
+
runId,
|
|
231
|
+
exitCode: null,
|
|
232
|
+
signal: null,
|
|
233
|
+
status: "failed",
|
|
234
|
+
startedAt,
|
|
235
|
+
completedAt: new Date().toISOString(),
|
|
236
|
+
durationMs: Date.now() - startMs,
|
|
237
|
+
errorMessage: err instanceof Error ? err.message : `${opts.providerType} execution failed`,
|
|
238
|
+
errorCode: null,
|
|
239
|
+
costUsd: null,
|
|
240
|
+
model,
|
|
241
|
+
summary: null,
|
|
242
|
+
sessionParams: sessionKey ? { sessionKey, gatewayUrl } : null,
|
|
243
|
+
sessionDisplayId: sessionKey,
|
|
244
|
+
clearSession: false,
|
|
245
|
+
billingType: null,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Session codec for HTTP-agent providers — round-trips `{ sessionKey, gatewayUrl }`. */
|
|
251
|
+
export const httpAgentSessionCodec: SessionCodec = {
|
|
252
|
+
deserialize(raw: unknown): Record<string, unknown> | null {
|
|
253
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
254
|
+
const obj = raw as Record<string, unknown>;
|
|
255
|
+
const sessionKey = str(obj["sessionKey"]) ?? str(obj["session_key"]);
|
|
256
|
+
if (!sessionKey) return null;
|
|
257
|
+
const gatewayUrl = str(obj["gatewayUrl"]);
|
|
258
|
+
return { sessionKey, ...(gatewayUrl ? { gatewayUrl } : {}) };
|
|
259
|
+
},
|
|
260
|
+
serialize(params: Record<string, unknown> | null): Record<string, unknown> | null {
|
|
261
|
+
if (!params) return null;
|
|
262
|
+
const sessionKey = str(params["sessionKey"]) ?? str(params["session_key"]);
|
|
263
|
+
if (!sessionKey) return null;
|
|
264
|
+
const gatewayUrl = str(params["gatewayUrl"]);
|
|
265
|
+
return { sessionKey, ...(gatewayUrl ? { gatewayUrl } : {}) };
|
|
266
|
+
},
|
|
267
|
+
getDisplayId(params: Record<string, unknown> | null): string | null {
|
|
268
|
+
if (!params) return null;
|
|
269
|
+
return str(params["sessionKey"]) ?? str(params["session_key"]);
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/** Build a `ProviderModule` for a remote HTTP agent gateway. */
|
|
274
|
+
export function httpAgentProvider(opts: HttpAgentOptions): ProviderModule {
|
|
275
|
+
async function resolveAuth(): Promise<AuthReport> {
|
|
276
|
+
// The gateway is a URL, not a local binary, so we can't probe presence here.
|
|
277
|
+
return {
|
|
278
|
+
providerType: opts.providerType,
|
|
279
|
+
binary: { installed: true },
|
|
280
|
+
options: [],
|
|
281
|
+
source: "filesystem",
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
type: opts.providerType,
|
|
286
|
+
capabilities: {
|
|
287
|
+
sessions: false,
|
|
288
|
+
modelDiscovery: false,
|
|
289
|
+
quotaProbing: false,
|
|
290
|
+
mcp: false,
|
|
291
|
+
skills: false,
|
|
292
|
+
instructions: false,
|
|
293
|
+
workspace: false,
|
|
294
|
+
planMode: false,
|
|
295
|
+
concurrentSend: false,
|
|
296
|
+
cancelQueuedMessage: false,
|
|
297
|
+
stopTask: false,
|
|
298
|
+
modes: false,
|
|
299
|
+
},
|
|
300
|
+
execute: (ctx) => runHttpAgent(opts, ctx),
|
|
301
|
+
resolveAuth,
|
|
302
|
+
sessionCodec: httpAgentSessionCodec,
|
|
303
|
+
};
|
|
304
|
+
}
|