create-loopengine 0.3.1 → 0.3.2
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/package.json +1 -1
- package/template/adapters/http.ts +30 -3
- package/template/package.json +1 -1
package/package.json
CHANGED
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
type AgentConfig,
|
|
68
68
|
type AgentModelConfig,
|
|
69
69
|
type ToolDefinition,
|
|
70
|
+
type Message,
|
|
70
71
|
type ModelContentBlock,
|
|
71
72
|
type RunAgentResult,
|
|
72
73
|
playgroundHtml,
|
|
@@ -120,6 +121,8 @@ import {
|
|
|
120
121
|
agentDirFor,
|
|
121
122
|
verifyProxyIdentity,
|
|
122
123
|
TRUSTED_PROXY_IDENTITY_HEADER,
|
|
124
|
+
reportRun,
|
|
125
|
+
usedTool,
|
|
123
126
|
NotifierFileError,
|
|
124
127
|
verifyDecisionToken,
|
|
125
128
|
decidePath,
|
|
@@ -1925,6 +1928,8 @@ async function executeUnattendedRun(agent: string, message: string, rawSessionId
|
|
|
1925
1928
|
async function reportWorkflowRun(run: WorkflowRun): Promise<void> {
|
|
1926
1929
|
const event: RunCallbackEvent | undefined = run.status === 'done' ? 'run.done' : run.status === 'error' ? 'run.failed' : run.status === 'awaiting_approval' ? 'run.awaiting_approval' : undefined
|
|
1927
1930
|
if (!event) return
|
|
1931
|
+
// For a host's run observer (core/run-events.ts); a failed run isn't reported.
|
|
1932
|
+
if (run.status !== 'error') reportRun({ agent: run.agent, source: 'workflow', id: run.run_id, via: run.source, usedTool: true })
|
|
1928
1933
|
const entry = getEntry(run.agent)
|
|
1929
1934
|
if (run.notify && entry && event !== 'run.awaiting_approval') {
|
|
1930
1935
|
const text = run.status === 'done' ? `Workflow ${run.workflow_id} for ${run.agent} ran:\n${run.result ?? ''}` : `Workflow ${run.workflow_id} for ${run.agent} failed: ${run.error ?? 'unknown error'}`
|
|
@@ -1942,7 +1947,12 @@ const workflowRunner = new WorkflowRunner({ execute: executeUnattendedRun, onCha
|
|
|
1942
1947
|
// A task that runs a workflow is also recorded as a run of that workflow,
|
|
1943
1948
|
// so the workflow's Recent runs shows its scheduled runs too.
|
|
1944
1949
|
function fireScheduledTask(task: ScheduledTask, rawSessionId: string): ReturnType<typeof executeUnattendedRun> {
|
|
1945
|
-
if (!task.workflow_id)
|
|
1950
|
+
if (!task.workflow_id) {
|
|
1951
|
+
return executeUnattendedRun(task.agent, task.message, rawSessionId).then((outcome) => {
|
|
1952
|
+
reportRun({ agent: task.agent, source: 'schedule', id: randomUUID(), usedTool: true })
|
|
1953
|
+
return outcome
|
|
1954
|
+
})
|
|
1955
|
+
}
|
|
1946
1956
|
return workflowRunner.runForSchedule({
|
|
1947
1957
|
agent: task.agent,
|
|
1948
1958
|
workflow_id: task.workflow_id,
|
|
@@ -2917,6 +2927,19 @@ async function raceAndRespond(res: ServerResponse, agentName: string, rawSession
|
|
|
2917
2927
|
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(responseBody))
|
|
2918
2928
|
}
|
|
2919
2929
|
|
|
2930
|
+
// Who sent a message, as a trusted proxy says in its signed identity:
|
|
2931
|
+
// an API key (role "api") or a signed-in person. Without a proxy, unknown.
|
|
2932
|
+
function messageCaller(req: IncomingMessage): 'api' | 'console' | 'unknown' {
|
|
2933
|
+
const identity = trustedProxySecret ? verifyProxyIdentity(req.headers[TRUSTED_PROXY_IDENTITY_HEADER], trustedProxySecret) : undefined
|
|
2934
|
+
if (!identity) return 'unknown'
|
|
2935
|
+
return identity.role === 'api' ? 'api' : 'console'
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
// For a host's run observer (core/run-events.ts).
|
|
2939
|
+
function reportMessageRun(req: IncomingMessage, agent: string, newMessages: Message[]): void {
|
|
2940
|
+
reportRun({ agent, source: 'message', id: randomUUID(), caller: messageCaller(req), usedTool: usedTool(newMessages) })
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2920
2943
|
async function handleMessages(req: IncomingMessage, res: ServerResponse, agentName: string): Promise<void> {
|
|
2921
2944
|
const parsed = await parseRequest(req, agentName)
|
|
2922
2945
|
if (!parsed.ok) {
|
|
@@ -2982,6 +3005,7 @@ async function handleMessages(req: IncomingMessage, res: ServerResponse, agentNa
|
|
|
2982
3005
|
pushSignal(state, { type: 'question', entry: question })
|
|
2983
3006
|
},
|
|
2984
3007
|
})
|
|
3008
|
+
reportMessageRun(req, agentName, result.newMessages)
|
|
2985
3009
|
if (result.pending) {
|
|
2986
3010
|
await createCheckpointFromPending(agentName, tenant, rawSessionId, result.pending)
|
|
2987
3011
|
}
|
|
@@ -3092,6 +3116,7 @@ async function handleMessagesStream(req: IncomingMessage, res: ServerResponse, a
|
|
|
3092
3116
|
pushSignal(state, { type: 'question', entry: question })
|
|
3093
3117
|
},
|
|
3094
3118
|
})
|
|
3119
|
+
reportMessageRun(req, agentName, result.newMessages)
|
|
3095
3120
|
if (result.pending) {
|
|
3096
3121
|
await createCheckpointFromPending(agentName, tenant, rawSessionId, result.pending)
|
|
3097
3122
|
}
|
|
@@ -3963,7 +3988,7 @@ function jobDeps(agentName: string, entry: RegistryEntry, connector: MessagingCo
|
|
|
3963
3988
|
connector,
|
|
3964
3989
|
plan: process.env.LOOPENGINE_PLAN,
|
|
3965
3990
|
allowed: (message) => jobAllowed(entry.config, app, message),
|
|
3966
|
-
runTurn: (sessionId, text) => runJobTurn(agentName, sessionId, text),
|
|
3991
|
+
runTurn: (sessionId, text) => runJobTurn(agentName, sessionId, text, connector.app === 'telegram' ? 'telegram' : 'slack'),
|
|
3967
3992
|
decideLink: (pendingId, kind) => {
|
|
3968
3993
|
const base = publicBaseUrl(connectionPublicUrl(entry.config, app))
|
|
3969
3994
|
return base ? `${base}${decidePath(pendingId, kind)}` : undefined
|
|
@@ -3998,7 +4023,7 @@ function jobTurnOf(text: string, pending: PendingSummary[] | undefined): JobTurn
|
|
|
3998
4023
|
}
|
|
3999
4024
|
|
|
4000
4025
|
// One turn of a job thread: the same session for the whole thread.
|
|
4001
|
-
async function runJobTurn(agent: string, rawSessionId: string, message: string): Promise<JobTurn> {
|
|
4026
|
+
async function runJobTurn(agent: string, rawSessionId: string, message: string, source: 'slack' | 'telegram'): Promise<JobTurn> {
|
|
4002
4027
|
const entry = getEntry(agent)
|
|
4003
4028
|
if (!entry) throw new Error(`no agent named "${agent}" in this project`)
|
|
4004
4029
|
const tenant = 'default'
|
|
@@ -4011,6 +4036,8 @@ async function runJobTurn(agent: string, rawSessionId: string, message: string):
|
|
|
4011
4036
|
approver: threadApprover,
|
|
4012
4037
|
questionHandler: threadQuestions,
|
|
4013
4038
|
})
|
|
4039
|
+
// For a host's run observer (core/run-events.ts).
|
|
4040
|
+
reportRun({ agent, source, id: randomUUID(), usedTool: usedTool(result.newMessages) })
|
|
4014
4041
|
if (result.pending) await createCheckpointFromPending(agent, tenant, rawSessionId, result.pending)
|
|
4015
4042
|
return { newMessages: result.newMessages, result: { text: result.text, pending: pendingSummary(result.pending) } }
|
|
4016
4043
|
})
|