@amodalai/runtime 0.3.48 → 0.3.50
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/src/agent/completion-tools.integration.test.d.ts +6 -0
- package/dist/src/agent/completion-tools.integration.test.js +263 -0
- package/dist/src/agent/completion-tools.integration.test.js.map +1 -0
- package/dist/src/agent/load-template-plan.integration.test.d.ts +6 -0
- package/dist/src/agent/load-template-plan.integration.test.js +152 -0
- package/dist/src/agent/load-template-plan.integration.test.js.map +1 -0
- package/dist/src/agent/local-server.js +64 -9
- package/dist/src/agent/local-server.js.map +1 -1
- package/dist/src/agent/loop-types.d.ts +12 -2
- package/dist/src/agent/loop.test.js +5 -2
- package/dist/src/agent/loop.test.js.map +1 -1
- package/dist/src/agent/propose-plan.integration.test.d.ts +6 -0
- package/dist/src/agent/propose-plan.integration.test.js +186 -0
- package/dist/src/agent/propose-plan.integration.test.js.map +1 -0
- package/dist/src/agent/routes/package-updates.d.ts +42 -0
- package/dist/src/agent/routes/package-updates.js +207 -0
- package/dist/src/agent/routes/package-updates.js.map +1 -0
- package/dist/src/agent/routes/package-updates.test.d.ts +6 -0
- package/dist/src/agent/routes/package-updates.test.js +25 -0
- package/dist/src/agent/routes/package-updates.test.js.map +1 -0
- package/dist/src/agent/setup-state.integration.test.d.ts +6 -0
- package/dist/src/agent/setup-state.integration.test.js +182 -0
- package/dist/src/agent/setup-state.integration.test.js.map +1 -0
- package/dist/src/agent/snapshot-server.js +1 -0
- package/dist/src/agent/snapshot-server.js.map +1 -1
- package/dist/src/agent/states/executing.d.ts +6 -0
- package/dist/src/agent/states/executing.js +63 -27
- package/dist/src/agent/states/executing.js.map +1 -1
- package/dist/src/agent/states/streaming.js +18 -2
- package/dist/src/agent/states/streaming.js.map +1 -1
- package/dist/src/agent/tool-executor-local.js +11 -2
- package/dist/src/agent/tool-executor-local.js.map +1 -1
- package/dist/src/agent/validate-connection.integration.test.d.ts +6 -0
- package/dist/src/agent/validate-connection.integration.test.js +160 -0
- package/dist/src/agent/validate-connection.integration.test.js.map +1 -0
- package/dist/src/api/create-agent.js +1 -0
- package/dist/src/api/create-agent.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/intent/executor.d.ts +48 -0
- package/dist/src/intent/executor.js +420 -0
- package/dist/src/intent/executor.js.map +1 -0
- package/dist/src/intent/executor.test.d.ts +6 -0
- package/dist/src/intent/executor.test.js +543 -0
- package/dist/src/intent/executor.test.js.map +1 -0
- package/dist/src/intent/index.d.ts +10 -0
- package/dist/src/intent/index.js +9 -0
- package/dist/src/intent/index.js.map +1 -0
- package/dist/src/intent/loader.d.ts +16 -0
- package/dist/src/intent/loader.js +112 -0
- package/dist/src/intent/loader.js.map +1 -0
- package/dist/src/intent/loader.test.d.ts +6 -0
- package/dist/src/intent/loader.test.js +86 -0
- package/dist/src/intent/loader.test.js.map +1 -0
- package/dist/src/intent/matcher.d.ts +26 -0
- package/dist/src/intent/matcher.js +29 -0
- package/dist/src/intent/matcher.js.map +1 -0
- package/dist/src/intent/matcher.test.d.ts +6 -0
- package/dist/src/intent/matcher.test.js +53 -0
- package/dist/src/intent/matcher.test.js.map +1 -0
- package/dist/src/intent/onboarding.e2e.test.d.ts +6 -0
- package/dist/src/intent/onboarding.e2e.test.js +394 -0
- package/dist/src/intent/onboarding.e2e.test.js.map +1 -0
- package/dist/src/routes/ai-stream.js +96 -3
- package/dist/src/routes/ai-stream.js.map +1 -1
- package/dist/src/routes/session-resolver.js +16 -0
- package/dist/src/routes/session-resolver.js.map +1 -1
- package/dist/src/session/credential-scrubber.d.ts +35 -0
- package/dist/src/session/credential-scrubber.js +150 -0
- package/dist/src/session/credential-scrubber.js.map +1 -0
- package/dist/src/session/credential-scrubber.test.d.ts +6 -0
- package/dist/src/session/credential-scrubber.test.js +192 -0
- package/dist/src/session/credential-scrubber.test.js.map +1 -0
- package/dist/src/session/manager.intent.test.d.ts +6 -0
- package/dist/src/session/manager.intent.test.js +197 -0
- package/dist/src/session/manager.intent.test.js.map +1 -0
- package/dist/src/session/manager.js +114 -0
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/session-builder.d.ts +16 -1
- package/dist/src/session/session-builder.js +209 -40
- package/dist/src/session/session-builder.js.map +1 -1
- package/dist/src/session/store.js +48 -2
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/tool-context-factory.js +12 -0
- package/dist/src/session/tool-context-factory.js.map +1 -1
- package/dist/src/session/types.d.ts +12 -1
- package/dist/src/setup/commit-setup.d.ts +94 -0
- package/dist/src/setup/commit-setup.js +154 -0
- package/dist/src/setup/commit-setup.js.map +1 -0
- package/dist/src/setup/commit-setup.test.d.ts +6 -0
- package/dist/src/setup/commit-setup.test.js +310 -0
- package/dist/src/setup/commit-setup.test.js.map +1 -0
- package/dist/src/tools/README.md +270 -0
- package/dist/src/tools/admin-tools.d.ts +27 -0
- package/dist/src/tools/admin-tools.js +734 -0
- package/dist/src/tools/admin-tools.js.map +1 -0
- package/dist/src/tools/agent-package-discovery.test.d.ts +6 -0
- package/dist/src/tools/agent-package-discovery.test.js +90 -0
- package/dist/src/tools/agent-package-discovery.test.js.map +1 -0
- package/dist/src/tools/builtin/ask-choice.d.ts +8 -0
- package/dist/src/tools/builtin/ask-choice.js +54 -0
- package/dist/src/tools/builtin/ask-choice.js.map +1 -0
- package/dist/src/tools/context.d.ts +154 -0
- package/dist/src/tools/context.js +30 -0
- package/dist/src/tools/context.js.map +1 -0
- package/dist/src/tools/custom-tool-adapter.d.ts +33 -2
- package/dist/src/tools/custom-tool-adapter.js +38 -1
- package/dist/src/tools/custom-tool-adapter.js.map +1 -1
- package/dist/src/tools/custom-tool-adapter.test.js +48 -0
- package/dist/src/tools/custom-tool-adapter.test.js.map +1 -1
- package/dist/src/tools/fetch-url-tool.js +2 -0
- package/dist/src/tools/fetch-url-tool.js.map +1 -1
- package/dist/src/tools/file-tools.js +16 -0
- package/dist/src/tools/file-tools.js.map +1 -1
- package/dist/src/tools/fs/local.test.d.ts +6 -0
- package/dist/src/tools/fs/local.test.js +126 -0
- package/dist/src/tools/fs/local.test.js.map +1 -0
- package/dist/src/tools/index.d.ts +35 -0
- package/dist/src/tools/index.js +11 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/mcp-tool-adapter.js +2 -0
- package/dist/src/tools/mcp-tool-adapter.js.map +1 -1
- package/dist/src/tools/memory-tool.js +23 -1
- package/dist/src/tools/memory-tool.js.map +1 -1
- package/dist/src/tools/permissions.d.ts +36 -0
- package/dist/src/tools/permissions.js +97 -0
- package/dist/src/tools/permissions.js.map +1 -0
- package/dist/src/tools/permissions.test.d.ts +6 -0
- package/dist/src/tools/permissions.test.js +62 -0
- package/dist/src/tools/permissions.test.js.map +1 -0
- package/dist/src/tools/request-tool.js +2 -0
- package/dist/src/tools/request-tool.js.map +1 -1
- package/dist/src/tools/sdk-context.d.ts +43 -0
- package/dist/src/tools/sdk-context.js +94 -0
- package/dist/src/tools/sdk-context.js.map +1 -0
- package/dist/src/tools/sdk-context.test.d.ts +6 -0
- package/dist/src/tools/sdk-context.test.js +134 -0
- package/dist/src/tools/sdk-context.test.js.map +1 -0
- package/dist/src/tools/store-tools.js +6 -0
- package/dist/src/tools/store-tools.js.map +1 -1
- package/dist/src/tools/types.d.ts +53 -14
- package/dist/src/tools/web-search-tool.js +2 -0
- package/dist/src/tools/web-search-tool.js.map +1 -1
- package/dist/src/types.d.ts +164 -28
- package/dist/src/types.js +9 -3
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -4
- package/dist/src/tools/agent-config-tool.d.ts +0 -7
- package/dist/src/tools/agent-config-tool.js +0 -78
- package/dist/src/tools/agent-config-tool.js.map +0 -1
- package/dist/src/tools/collect-secret-tool.d.ts +0 -7
- package/dist/src/tools/collect-secret-tool.js +0 -47
- package/dist/src/tools/collect-secret-tool.js.map +0 -1
- package/dist/src/tools/fs/http.d.ts +0 -37
- package/dist/src/tools/fs/http.js +0 -88
- package/dist/src/tools/fs/http.js.map +0 -1
- package/dist/src/tools/http-file-tools.d.ts +0 -13
- package/dist/src/tools/http-file-tools.js +0 -146
- package/dist/src/tools/http-file-tools.js.map +0 -1
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Phase E.3 + E.4 + E.10 integration test. Pins the agent-admin
|
|
8
|
+
* completion tools end-to-end through the actual runtime path:
|
|
9
|
+
* LocalToolExecutor compiles each handler.ts via esbuild, dynamic-imports
|
|
10
|
+
* the resulting .mjs, and runs it with a CustomToolContext whose
|
|
11
|
+
* completion ops are backed by the real commitSetup primitive +
|
|
12
|
+
* deleteSetupState query (against a temp Postgres + temp repo).
|
|
13
|
+
*
|
|
14
|
+
* Skips when DATABASE_URL or the agent-admin cache isn't populated.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync } from 'node:fs';
|
|
17
|
+
import { randomUUID } from 'node:crypto';
|
|
18
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
19
|
+
import { homedir, tmpdir } from 'node:os';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
|
22
|
+
import { and, eq } from 'drizzle-orm';
|
|
23
|
+
import { closeDb, deleteSetupState, ensureSchema, getDb, setupState, upsertSetupState, } from '@amodalai/db';
|
|
24
|
+
import { LocalFsBackend } from '../tools/fs/local.js';
|
|
25
|
+
import { commitSetup } from '../setup/commit-setup.js';
|
|
26
|
+
import { LocalToolExecutor } from './tool-executor-local.js';
|
|
27
|
+
const ADMIN_AGENT_PATH = path.join(homedir(), '.amodal', 'admin-agent', 'latest');
|
|
28
|
+
const REQUEST_HANDLER = path.join(ADMIN_AGENT_PATH, 'tools', 'request_complete_setup', 'handler.ts');
|
|
29
|
+
const FORCE_HANDLER = path.join(ADMIN_AGENT_PATH, 'tools', 'force_complete_setup', 'handler.ts');
|
|
30
|
+
const CANCEL_HANDLER = path.join(ADMIN_AGENT_PATH, 'tools', 'cancel_setup', 'handler.ts');
|
|
31
|
+
const HAS_DEPS = Boolean(process.env['DATABASE_URL']) &&
|
|
32
|
+
existsSync(REQUEST_HANDLER) &&
|
|
33
|
+
existsSync(FORCE_HANDLER) &&
|
|
34
|
+
existsSync(CANCEL_HANDLER);
|
|
35
|
+
const describeWhenReady = HAS_DEPS ? describe : describe.skip;
|
|
36
|
+
function makePlan(overrides) {
|
|
37
|
+
return {
|
|
38
|
+
templatePackage: '@amodalai/test-template',
|
|
39
|
+
slots: [],
|
|
40
|
+
config: [],
|
|
41
|
+
completion: { title: 'Test Agent', suggestions: [], automationTitle: null },
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const slackSlot = {
|
|
46
|
+
label: 'Slack',
|
|
47
|
+
description: 'Where the digest gets posted.',
|
|
48
|
+
required: true,
|
|
49
|
+
multi: false,
|
|
50
|
+
options: [
|
|
51
|
+
{
|
|
52
|
+
packageName: '@amodalai/connection-slack',
|
|
53
|
+
displayName: 'Slack',
|
|
54
|
+
authType: 'bearer',
|
|
55
|
+
oauthScopes: [],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
describeWhenReady('completion tools (Phase E.3 / E.4 / E.10 integration)', () => {
|
|
60
|
+
let db;
|
|
61
|
+
let repoRoot;
|
|
62
|
+
let fs;
|
|
63
|
+
let executor;
|
|
64
|
+
let agentId;
|
|
65
|
+
const scopeId = '';
|
|
66
|
+
beforeAll(async () => {
|
|
67
|
+
db = getDb();
|
|
68
|
+
await ensureSchema(db);
|
|
69
|
+
});
|
|
70
|
+
afterAll(async () => {
|
|
71
|
+
await closeDb();
|
|
72
|
+
});
|
|
73
|
+
beforeEach(async () => {
|
|
74
|
+
repoRoot = await mkdtemp(path.join(tmpdir(), 'completion-'));
|
|
75
|
+
fs = new LocalFsBackend({ repoRoot });
|
|
76
|
+
executor = new LocalToolExecutor();
|
|
77
|
+
agentId = `agent_${randomUUID()}`;
|
|
78
|
+
});
|
|
79
|
+
afterEach(async () => {
|
|
80
|
+
executor.dispose();
|
|
81
|
+
try {
|
|
82
|
+
await deleteSetupState(db, agentId, scopeId);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Best-effort.
|
|
86
|
+
}
|
|
87
|
+
await rm(repoRoot, { recursive: true, force: true });
|
|
88
|
+
});
|
|
89
|
+
function loadedTool(handlerPath, name) {
|
|
90
|
+
return {
|
|
91
|
+
name,
|
|
92
|
+
description: `${name} test`,
|
|
93
|
+
parameters: {},
|
|
94
|
+
confirm: false,
|
|
95
|
+
timeout: 10_000,
|
|
96
|
+
env: [],
|
|
97
|
+
handlerPath,
|
|
98
|
+
location: path.dirname(handlerPath),
|
|
99
|
+
hasPackageJson: false,
|
|
100
|
+
hasSetupScript: false,
|
|
101
|
+
hasRequirementsTxt: false,
|
|
102
|
+
hasDockerfile: false,
|
|
103
|
+
sandboxLanguage: 'typescript',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function buildCompletionOps() {
|
|
107
|
+
return {
|
|
108
|
+
async commit(opts) {
|
|
109
|
+
const result = await commitSetup({
|
|
110
|
+
db,
|
|
111
|
+
fs,
|
|
112
|
+
agentId,
|
|
113
|
+
scopeId,
|
|
114
|
+
force: opts?.force ?? false,
|
|
115
|
+
});
|
|
116
|
+
if (result.ok) {
|
|
117
|
+
return {
|
|
118
|
+
ok: true,
|
|
119
|
+
alreadyComplete: result.alreadyComplete,
|
|
120
|
+
completedAt: result.completedAt.toISOString(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (result.reason === 'not_ready') {
|
|
124
|
+
return { ok: false, reason: 'not_ready', warnings: result.warnings };
|
|
125
|
+
}
|
|
126
|
+
return { ok: false, reason: 'no_state', message: result.message };
|
|
127
|
+
},
|
|
128
|
+
async cancel() {
|
|
129
|
+
const deleted = await deleteSetupState(db, agentId, scopeId);
|
|
130
|
+
return { ok: true, deleted };
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function buildCtx(opts) {
|
|
135
|
+
const completion = opts && Object.prototype.hasOwnProperty.call(opts, 'completion')
|
|
136
|
+
? opts.completion
|
|
137
|
+
: buildCompletionOps();
|
|
138
|
+
return {
|
|
139
|
+
async request() {
|
|
140
|
+
throw new Error('not used');
|
|
141
|
+
},
|
|
142
|
+
async exec() {
|
|
143
|
+
throw new Error('not used');
|
|
144
|
+
},
|
|
145
|
+
async store() {
|
|
146
|
+
throw new Error('not used');
|
|
147
|
+
},
|
|
148
|
+
env: () => undefined,
|
|
149
|
+
log: () => undefined,
|
|
150
|
+
signal: AbortSignal.timeout(30_000),
|
|
151
|
+
agentId,
|
|
152
|
+
scopeId,
|
|
153
|
+
sessionId: 'sess_test',
|
|
154
|
+
...(completion ? { completion } : {}),
|
|
155
|
+
...(opts?.emitCapture
|
|
156
|
+
? {
|
|
157
|
+
emit: (event) => {
|
|
158
|
+
opts.emitCapture?.push(event);
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
: {}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// -------------------------------------------------------------------
|
|
165
|
+
// request_complete_setup (E.3)
|
|
166
|
+
// -------------------------------------------------------------------
|
|
167
|
+
it('request_complete_setup returns not_ready with warnings when slots are missing', async () => {
|
|
168
|
+
await upsertSetupState(db, agentId, scopeId, {
|
|
169
|
+
phase: 'configuring',
|
|
170
|
+
plan: makePlan({ slots: [slackSlot] }),
|
|
171
|
+
});
|
|
172
|
+
const result = await executor.execute(loadedTool(REQUEST_HANDLER, 'request_complete_setup'), {}, buildCtx());
|
|
173
|
+
expect(result).toMatchObject({ ok: false, reason: 'not_ready' });
|
|
174
|
+
const r = result;
|
|
175
|
+
expect(r.warnings[0]?.target).toBe('Slack');
|
|
176
|
+
// amodal.json was NOT written.
|
|
177
|
+
await expect(readFile(path.join(repoRoot, 'amodal.json'), 'utf-8')).rejects.toThrow();
|
|
178
|
+
});
|
|
179
|
+
it('request_complete_setup commits when validation passes and writes amodal.json', async () => {
|
|
180
|
+
await upsertSetupState(db, agentId, scopeId, {
|
|
181
|
+
phase: 'configuring',
|
|
182
|
+
plan: makePlan({
|
|
183
|
+
slots: [slackSlot],
|
|
184
|
+
completion: { title: 'Slackbot', suggestions: [], automationTitle: null },
|
|
185
|
+
}),
|
|
186
|
+
appendCompleted: [
|
|
187
|
+
{
|
|
188
|
+
slotLabel: 'Slack',
|
|
189
|
+
packageName: '@amodalai/connection-slack',
|
|
190
|
+
connectedAt: new Date().toISOString(),
|
|
191
|
+
validatedAt: new Date().toISOString(),
|
|
192
|
+
validationFormatted: 'Found 12 channels',
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
});
|
|
196
|
+
const result = await executor.execute(loadedTool(REQUEST_HANDLER, 'request_complete_setup'), {}, buildCtx());
|
|
197
|
+
expect(result).toMatchObject({ ok: true, alreadyComplete: false });
|
|
198
|
+
const written = JSON.parse(await readFile(path.join(repoRoot, 'amodal.json'), 'utf-8'));
|
|
199
|
+
expect(written.name).toBe('slackbot');
|
|
200
|
+
expect(written.packages).toContain('@amodalai/connection-slack');
|
|
201
|
+
});
|
|
202
|
+
it('request_complete_setup is idempotent — second call returns alreadyComplete:true', async () => {
|
|
203
|
+
await upsertSetupState(db, agentId, scopeId, {
|
|
204
|
+
phase: 'configuring',
|
|
205
|
+
plan: makePlan(),
|
|
206
|
+
});
|
|
207
|
+
const r1 = await executor.execute(loadedTool(REQUEST_HANDLER, 'request_complete_setup'), {}, buildCtx());
|
|
208
|
+
const r2 = await executor.execute(loadedTool(REQUEST_HANDLER, 'request_complete_setup'), {}, buildCtx());
|
|
209
|
+
expect(r1).toMatchObject({ ok: true });
|
|
210
|
+
expect(r2).toMatchObject({ ok: true, alreadyComplete: true });
|
|
211
|
+
});
|
|
212
|
+
it('request_complete_setup returns no_ops when ctx.completion is absent', async () => {
|
|
213
|
+
const result = await executor.execute(loadedTool(REQUEST_HANDLER, 'request_complete_setup'), {}, buildCtx({ completion: null }));
|
|
214
|
+
expect(result).toMatchObject({ ok: false, reason: 'no_ops' });
|
|
215
|
+
});
|
|
216
|
+
// -------------------------------------------------------------------
|
|
217
|
+
// force_complete_setup (E.4)
|
|
218
|
+
// -------------------------------------------------------------------
|
|
219
|
+
it('force_complete_setup commits even with missing required slots', async () => {
|
|
220
|
+
await upsertSetupState(db, agentId, scopeId, {
|
|
221
|
+
phase: 'configuring',
|
|
222
|
+
plan: makePlan({ slots: [slackSlot] }),
|
|
223
|
+
});
|
|
224
|
+
const result = await executor.execute(loadedTool(FORCE_HANDLER, 'force_complete_setup'), {}, buildCtx());
|
|
225
|
+
expect(result).toMatchObject({ ok: true, alreadyComplete: false });
|
|
226
|
+
const written = await readFile(path.join(repoRoot, 'amodal.json'), 'utf-8');
|
|
227
|
+
expect(written.length).toBeGreaterThan(0);
|
|
228
|
+
});
|
|
229
|
+
// -------------------------------------------------------------------
|
|
230
|
+
// cancel_setup (E.10)
|
|
231
|
+
// -------------------------------------------------------------------
|
|
232
|
+
it('cancel_setup deletes the row + emits a setup_cancelled SSE event', async () => {
|
|
233
|
+
await upsertSetupState(db, agentId, scopeId, { phase: 'planning' });
|
|
234
|
+
const captured = [];
|
|
235
|
+
const result = await executor.execute(loadedTool(CANCEL_HANDLER, 'cancel_setup'), { reason: 'wants a different template' }, buildCtx({ emitCapture: captured }));
|
|
236
|
+
expect(result).toMatchObject({ ok: true, deleted: true });
|
|
237
|
+
expect(captured).toHaveLength(1);
|
|
238
|
+
const event = captured[0];
|
|
239
|
+
if (event.type !== 'setup_cancelled')
|
|
240
|
+
throw new Error('expected setup_cancelled');
|
|
241
|
+
expect(event.reason).toBe('wants a different template');
|
|
242
|
+
// Row is gone.
|
|
243
|
+
const fresh = await db
|
|
244
|
+
.select()
|
|
245
|
+
.from(setupState)
|
|
246
|
+
.where(and(eq(setupState.agentId, agentId), eq(setupState.scopeId, scopeId)));
|
|
247
|
+
expect(fresh).toHaveLength(0);
|
|
248
|
+
});
|
|
249
|
+
it('cancel_setup returns deleted: false when no row existed', async () => {
|
|
250
|
+
const captured = [];
|
|
251
|
+
const result = await executor.execute(loadedTool(CANCEL_HANDLER, 'cancel_setup'), {}, buildCtx({ emitCapture: captured }));
|
|
252
|
+
expect(result).toMatchObject({ ok: true, deleted: false });
|
|
253
|
+
// The setup_cancelled event still fires — the agent emitting it
|
|
254
|
+
// is signaling intent, not confirming a row delete; Studio
|
|
255
|
+
// should flip to picker either way.
|
|
256
|
+
expect(captured).toHaveLength(1);
|
|
257
|
+
});
|
|
258
|
+
it('cancel_setup returns no_ops when ctx.completion is absent', async () => {
|
|
259
|
+
const result = await executor.execute(loadedTool(CANCEL_HANDLER, 'cancel_setup'), {}, buildCtx({ completion: null }));
|
|
260
|
+
expect(result).toMatchObject({ ok: false, reason: 'no_ops' });
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
//# sourceMappingURL=completion-tools.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-tools.integration.test.js","sourceRoot":"","sources":["../../../src/agent/completion-tools.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Phase C integration test for `load_template_plan`. Pins the
|
|
8
|
+
* end-to-end runtime path: LocalToolExecutor compiles the
|
|
9
|
+
* agent-admin handler via esbuild, dynamic-imports the resulting
|
|
10
|
+
* .mjs, and runs it with a CustomToolContext carrying a real
|
|
11
|
+
* `ctx.plan.compose` ops object backed by `composePlan` from
|
|
12
|
+
* `@amodalai/core`.
|
|
13
|
+
*
|
|
14
|
+
* The test sets up a synthetic repo with a fake template package +
|
|
15
|
+
* connection packages so the entire compose chain runs against real
|
|
16
|
+
* disk reads. Skips when the agent-admin cache isn't populated.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
20
|
+
import { homedir, tmpdir } from 'node:os';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
23
|
+
import { composePlan } from '@amodalai/core';
|
|
24
|
+
import { LocalToolExecutor } from './tool-executor-local.js';
|
|
25
|
+
const ADMIN_AGENT_PATH = path.join(homedir(), '.amodal', 'admin-agent', 'latest');
|
|
26
|
+
const HANDLER = path.join(ADMIN_AGENT_PATH, 'tools', 'load_template_plan', 'handler.ts');
|
|
27
|
+
const HAS_HANDLER = existsSync(HANDLER);
|
|
28
|
+
const describeWhenReady = HAS_HANDLER ? describe : describe.skip;
|
|
29
|
+
describeWhenReady('load_template_plan (Phase C integration)', () => {
|
|
30
|
+
let repoRoot;
|
|
31
|
+
let executor;
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
repoRoot = await mkdtemp(path.join(tmpdir(), 'phase-c-'));
|
|
34
|
+
executor = new LocalToolExecutor();
|
|
35
|
+
});
|
|
36
|
+
afterEach(async () => {
|
|
37
|
+
executor.dispose();
|
|
38
|
+
await rm(repoRoot, { recursive: true, force: true });
|
|
39
|
+
});
|
|
40
|
+
function loadedTool() {
|
|
41
|
+
return {
|
|
42
|
+
name: 'load_template_plan',
|
|
43
|
+
description: 'load_template_plan test',
|
|
44
|
+
parameters: {},
|
|
45
|
+
confirm: false,
|
|
46
|
+
timeout: 10_000,
|
|
47
|
+
env: [],
|
|
48
|
+
handlerPath: HANDLER,
|
|
49
|
+
location: path.dirname(HANDLER),
|
|
50
|
+
hasPackageJson: false,
|
|
51
|
+
hasSetupScript: false,
|
|
52
|
+
hasRequirementsTxt: false,
|
|
53
|
+
hasDockerfile: false,
|
|
54
|
+
sandboxLanguage: 'typescript',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function buildPlanOps() {
|
|
58
|
+
return {
|
|
59
|
+
async compose(templatePackageName) {
|
|
60
|
+
try {
|
|
61
|
+
const composed = await composePlan({ repoPath: repoRoot, templatePackage: templatePackageName });
|
|
62
|
+
return { ok: true, plan: composed };
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (err !== null &&
|
|
66
|
+
typeof err === 'object' &&
|
|
67
|
+
'code' in err &&
|
|
68
|
+
err.code === 'CONFIG_NOT_FOUND') {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
reason: 'not_installed',
|
|
72
|
+
message: `Template "${templatePackageName}" is not installed.`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
reason: 'malformed',
|
|
78
|
+
message: err instanceof Error ? err.message : String(err),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function buildCtx(opts) {
|
|
85
|
+
// null = explicitly omit ctx.plan; undefined / missing = use the default real ops.
|
|
86
|
+
const planOps = opts && Object.prototype.hasOwnProperty.call(opts, 'planOps')
|
|
87
|
+
? opts.planOps
|
|
88
|
+
: buildPlanOps();
|
|
89
|
+
return {
|
|
90
|
+
async request() {
|
|
91
|
+
throw new Error('not used');
|
|
92
|
+
},
|
|
93
|
+
async exec() {
|
|
94
|
+
throw new Error('not used');
|
|
95
|
+
},
|
|
96
|
+
async store() {
|
|
97
|
+
throw new Error('not used');
|
|
98
|
+
},
|
|
99
|
+
env: () => undefined,
|
|
100
|
+
log: () => undefined,
|
|
101
|
+
signal: AbortSignal.timeout(30_000),
|
|
102
|
+
agentId: 'agent_test',
|
|
103
|
+
scopeId: '',
|
|
104
|
+
sessionId: 'sess_test',
|
|
105
|
+
...(planOps ? { plan: planOps } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async function writeJson(rel, value) {
|
|
109
|
+
const full = path.join(repoRoot, rel);
|
|
110
|
+
await mkdir(path.dirname(full), { recursive: true });
|
|
111
|
+
await writeFile(full, JSON.stringify(value), 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
it('returns a SetupPlan composed from the template + connection packages', async () => {
|
|
114
|
+
await writeJson('node_modules/@amodalai/test-template/template.json', {
|
|
115
|
+
connections: [
|
|
116
|
+
{
|
|
117
|
+
label: 'Slack',
|
|
118
|
+
description: 'Where the digest gets posted.',
|
|
119
|
+
options: ['@amodalai/connection-slack'],
|
|
120
|
+
required: true,
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
await writeJson('node_modules/@amodalai/connection-slack/package.json', {
|
|
125
|
+
name: '@amodalai/connection-slack',
|
|
126
|
+
amodal: {
|
|
127
|
+
displayName: 'Slack',
|
|
128
|
+
auth: { type: 'bearer' },
|
|
129
|
+
oauth: { scopes: ['chat:write'] },
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
const result = await executor.execute(loadedTool(), { packageName: '@amodalai/test-template' }, buildCtx());
|
|
133
|
+
const r = result;
|
|
134
|
+
expect(r.ok).toBe(true);
|
|
135
|
+
expect(r.plan.slots).toHaveLength(1);
|
|
136
|
+
expect(r.plan.slots[0].label).toBe('Slack');
|
|
137
|
+
expect(r.plan.slots[0].options[0].displayName).toBe('Slack');
|
|
138
|
+
});
|
|
139
|
+
it('surfaces not_installed soft-fail when the template is missing', async () => {
|
|
140
|
+
const result = await executor.execute(loadedTool(), { packageName: '@amodalai/never-installed' }, buildCtx());
|
|
141
|
+
expect(result).toMatchObject({ ok: false, reason: 'not_installed' });
|
|
142
|
+
});
|
|
143
|
+
it('rejects path-traversal package names without filesystem access', async () => {
|
|
144
|
+
const result = await executor.execute(loadedTool(), { packageName: '../../etc/passwd' }, buildCtx());
|
|
145
|
+
expect(result).toMatchObject({ ok: false, reason: 'error' });
|
|
146
|
+
});
|
|
147
|
+
it('returns no_ops when ctx.plan is absent', async () => {
|
|
148
|
+
const result = await executor.execute(loadedTool(), { packageName: '@amodalai/test' }, buildCtx({ planOps: null }));
|
|
149
|
+
expect(result).toMatchObject({ ok: false, reason: 'no_ops' });
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=load-template-plan.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-template-plan.integration.test.js","sourceRoot":"","sources":["../../../src/agent/load-template-plan.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* for config changes (hot reload).
|
|
12
12
|
*/
|
|
13
13
|
import express from 'express';
|
|
14
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
14
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, watch } from 'node:fs';
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
17
|
import { randomUUID } from 'node:crypto';
|
|
@@ -67,6 +67,7 @@ import { createChatStreamRouter } from '../routes/chat-stream.js';
|
|
|
67
67
|
import { createChatRouter } from '../routes/chat.js';
|
|
68
68
|
import { createTaskRouter } from './routes/task.js';
|
|
69
69
|
import { createInspectRouter } from './routes/inspect.js';
|
|
70
|
+
import { createPackageUpdatesRouter } from './routes/package-updates.js';
|
|
70
71
|
import { createFeedbackRouter } from './routes/feedback.js';
|
|
71
72
|
import { FeedbackStore } from './feedback-store.js';
|
|
72
73
|
import { createStoresRouter } from './routes/stores.js';
|
|
@@ -326,6 +327,7 @@ export async function createLocalServer(config) {
|
|
|
326
327
|
systemPrompt: components.systemPrompt,
|
|
327
328
|
toolContextFactory: components.toolContextFactory,
|
|
328
329
|
appId,
|
|
330
|
+
intents: components.intents,
|
|
329
331
|
});
|
|
330
332
|
return { session, toolContextFactory: components.toolContextFactory };
|
|
331
333
|
};
|
|
@@ -510,6 +512,19 @@ export async function createLocalServer(config) {
|
|
|
510
512
|
}
|
|
511
513
|
return out;
|
|
512
514
|
}
|
|
515
|
+
// ---------------------------------------------------------------------------
|
|
516
|
+
// /api/oauth/start + /api/oauth/callback — DEPRECATED
|
|
517
|
+
//
|
|
518
|
+
// OAuth start/callback moved to Studio (packages/studio/src/server/routes/oauth.ts).
|
|
519
|
+
// Studio is the boot surface — it's up before `amodal.json` exists, so the
|
|
520
|
+
// setup-time Configure flow can run before this runtime even starts. The
|
|
521
|
+
// runtime now watches `<repoPath>/.amodal/secrets.env` for changes and
|
|
522
|
+
// reloads `process.env` automatically when Studio writes a new credential.
|
|
523
|
+
//
|
|
524
|
+
// These handlers stay in for backward compat (any older Studio build or
|
|
525
|
+
// direct caller) but are no longer the canonical path. Plan: remove after
|
|
526
|
+
// one release.
|
|
527
|
+
// ---------------------------------------------------------------------------
|
|
513
528
|
app.get('/api/oauth/start', (req, res) => {
|
|
514
529
|
void (async () => {
|
|
515
530
|
reapExpiredOauthStates();
|
|
@@ -628,13 +643,31 @@ export async function createLocalServer(config) {
|
|
|
628
643
|
res.status(500).json({ error: msg });
|
|
629
644
|
});
|
|
630
645
|
});
|
|
631
|
-
// Load any previously-persisted
|
|
632
|
-
//
|
|
633
|
-
//
|
|
646
|
+
// Load any previously-persisted secrets into process.env on startup,
|
|
647
|
+
// then watch the file for changes — Studio writes to this file when
|
|
648
|
+
// it completes an OAuth dance or saves a paste-field, so the runtime
|
|
649
|
+
// needs to pick up new credentials without a restart.
|
|
650
|
+
//
|
|
651
|
+
// Path resolution: the admin agent is spawned with `cwd: <admin
|
|
652
|
+
// agent dir>` but `REPO_PATH=<user's repo>` in env. We want to
|
|
653
|
+
// watch the USER's secrets.env in both cases (main runtime and
|
|
654
|
+
// admin agent), so prefer REPO_PATH when set. Falls back to
|
|
655
|
+
// config.repoPath, which is the right path for the main runtime.
|
|
634
656
|
{
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
657
|
+
const secretsRepoPath = process.env['REPO_PATH'] ?? config.repoPath;
|
|
658
|
+
const dir = path.join(secretsRepoPath, '.amodal');
|
|
659
|
+
const file = path.join(dir, 'secrets.env');
|
|
660
|
+
function loadSecrets(reason) {
|
|
661
|
+
if (!existsSync(file))
|
|
662
|
+
return;
|
|
663
|
+
let content;
|
|
664
|
+
try {
|
|
665
|
+
content = readFileSync(file, 'utf-8');
|
|
666
|
+
}
|
|
667
|
+
catch (err) {
|
|
668
|
+
log.warn('secrets_read_failed', { file, error: err instanceof Error ? err.message : String(err) });
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
638
671
|
let count = 0;
|
|
639
672
|
for (const line of content.split('\n')) {
|
|
640
673
|
const eq = line.indexOf('=');
|
|
@@ -647,8 +680,28 @@ export async function createLocalServer(config) {
|
|
|
647
680
|
count++;
|
|
648
681
|
}
|
|
649
682
|
}
|
|
650
|
-
if (count > 0)
|
|
651
|
-
log.info('secrets_loaded_from_disk', { count, file });
|
|
683
|
+
if (count > 0) {
|
|
684
|
+
log.info(reason === 'startup' ? 'secrets_loaded_from_disk' : 'secrets_reloaded_from_disk', { count, file });
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
loadSecrets('startup');
|
|
688
|
+
// Watch the parent dir (not the file directly) so we still pick up
|
|
689
|
+
// the first write — fs.watch on a non-existent file throws, and
|
|
690
|
+
// editor-style "atomic save" replaces the inode which most
|
|
691
|
+
// file-watchers miss when scoped to the path.
|
|
692
|
+
if (existsSync(dir)) {
|
|
693
|
+
try {
|
|
694
|
+
const watcher = watch(dir, { persistent: false }, (_event, filename) => {
|
|
695
|
+
if (filename === 'secrets.env')
|
|
696
|
+
loadSecrets('change');
|
|
697
|
+
});
|
|
698
|
+
watcher.on('error', (err) => {
|
|
699
|
+
log.warn('secrets_watcher_error', { file, error: err.message });
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
catch (err) {
|
|
703
|
+
log.warn('secrets_watch_failed', { dir, error: err instanceof Error ? err.message : String(err) });
|
|
704
|
+
}
|
|
652
705
|
}
|
|
653
706
|
}
|
|
654
707
|
// ---- Secrets write + per-connection detail -----------------------------
|
|
@@ -911,6 +964,8 @@ export async function createLocalServer(config) {
|
|
|
911
964
|
app.use(createTaskRouter({ sessionManager, createTaskSession: createTaskSessionComponents }));
|
|
912
965
|
// Inspect
|
|
913
966
|
app.use(createInspectRouter({ getBundle, repoPath: config.repoPath }));
|
|
967
|
+
// Package updates (npm view + cache)
|
|
968
|
+
app.use(createPackageUpdatesRouter({ repoPath: config.repoPath, logger: log }));
|
|
914
969
|
// Messaging channels
|
|
915
970
|
if (channelsResult) {
|
|
916
971
|
app.use('/channels', channelsResult.router);
|