Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/cli/lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ class InvalidArgumentsError extends Error {
}
}

export const POST_AUTH_HELP_MESSAGE = `Hi, I’m CALL-E 👋

I can help make phone calls, gather information, and handle phone-based tasks like appointments, reservations, follow-ups, and customer service requests.

Before each call, I’ll confirm the goal and key details with you. Afterward, I’ll share the status, summary, key takeaways, and next steps.`;

const POST_AUTH_HELP_HINT_TYPE = "post_auth_help";

function printHelp(stdout) {
stdout(`Usage: calle <command> [options]

Expand Down Expand Up @@ -164,14 +172,26 @@ function assertNoUnexpectedPositional(positional) {
}
}

function postAuthAssistantHint(status) {
if (status !== "logged_in" && status !== "cached") {
return null;
}
return {
type: POST_AUTH_HELP_HINT_TYPE,
message: POST_AUTH_HELP_MESSAGE,
};
}

function publicLoginPayload({ config, cachePath, pendingPath, tokenDocument, status }) {
const assistantHint = postAuthAssistantHint(status);
return {
status,
broker_base_url: config.brokerBaseUrl,
server_url: config.serverUrl,
cache_path: cachePath,
pending_cache_path: pendingPath,
expires_at: tokenDocument?.expires_at ?? null,
...(assistantHint ? { assistant_hint: assistantHint } : {}),
};
}

Expand Down
31 changes: 30 additions & 1 deletion packages/cli/test/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import path from "node:path";
import test from "node:test";
import assert from "node:assert/strict";

import { runCli } from "../lib/cli.js";
import { POST_AUTH_HELP_MESSAGE, runCli } from "../lib/cli.js";
import { pendingCachePath, tokenCachePath, writePrivateJson } from "../lib/cache.js";
import { CLI_VERSION } from "../lib/config.js";

Expand Down Expand Up @@ -114,11 +114,40 @@ test("auth login defaults broker payload to openagent_oauth and hides token from
const payload = JSON.parse(result.stdout);
assert.equal(payload.status, "logged_in");
assert.equal(payload.server_url, "https://mcp.example/mcp/openagent_oauth");
assert.deepEqual(payload.assistant_hint, {
type: "post_auth_help",
message: POST_AUTH_HELP_MESSAGE,
});
assert.match(payload.assistant_hint.message, /I can help make phone calls/);
const tokenPayload = JSON.parse(fs.readFileSync(tokenCachePath(cacheRoot, payload.server_url), "utf8"));
assert.equal(tokenPayload.token.access_token, "secret-token");
assert.equal(fs.existsSync(pendingCachePath(cacheRoot, payload.server_url)), false);
});

test("auth login returns post-auth assistant hint for cached login", async () => {
const cacheRoot = makeTempRoot("calle-cli-cached-login");
const serverUrl = "https://mcp.example/mcp/openagent_oauth";
writeToken(cacheRoot, serverUrl, "cached-login-token");

const result = await run(
["auth", "login", "--base-url", "https://mcp.example", "--cache-root", cacheRoot],
{
fetchImpl: async () => {
throw new Error("auth login should not contact broker with a usable cached token");
},
}
);

assert.equal(result.code, 0);
assert.doesNotMatch(result.stdout, /cached-login-token/);
const payload = JSON.parse(result.stdout);
assert.equal(payload.status, "cached");
assert.deepEqual(payload.assistant_hint, {
type: "post_auth_help",
message: POST_AUTH_HELP_MESSAGE,
});
});

test("auth login forwards upstream integration context from environment", async () => {
const cacheRoot = makeTempRoot("calle-cli-login-integration");
const seenHeaders = [];
Expand Down
4 changes: 4 additions & 0 deletions packages/codex-plugin/plugin/skills/calle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ when the user asks to verify Call-E setup:
3. If auth is missing or expired, run or suggest `auth login`.
4. After login completes, run `mcp tools`.
5. Confirm that `plan_call`, `run_call`, and `get_call_run` are available.
6. If the successful `auth login` JSON included `assistant_hint.message`, use
it to include a brief post-auth help note in the next user-facing reply
after tool availability is confirmed. Adapt the wording naturally to the
user's language and context.

Setup verification must not place a real phone call. Use only help, auth, and
tool-listing commands until the user asks for a call workflow.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ Rules:
- If a command returns `auth_required`, run or suggest `auth login`.
- If `mcp tools` succeeds, confirm that `plan_call`, `run_call`, and
`get_call_run` are present.
- If successful `auth login` output includes `assistant_hint.message`, use it
to include a brief post-auth help note in the next user-facing reply after
`mcp tools` confirms the required tools are present. Adapt the wording
naturally to the user's language and context.
- Do not run `call run` during setup verification.
- Do not use `.mcp.json`, raw HTTP, or direct remote MCP configuration in this
plugin version.
Expand Down
5 changes: 5 additions & 0 deletions packages/codex-plugin/scripts/check-plugin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ function checkSkill({ skillName, skillDir, failures }) {
const source = fs.readFileSync(skillFile, "utf8");
const frontmatter = extractFrontmatter(source);
assert(frontmatter, failures, `${skillFile} must start with YAML frontmatter.`);
assert(
source.includes("assistant_hint.message"),
failures,
`${skillFile} must document how to display assistant_hint.message after auth login.`,
);

if (!frontmatter) {
return;
Expand Down
2 changes: 1 addition & 1 deletion packages/codex-plugin/test/check-plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function createValidFixture(root) {

writeFile(
path.join(packageRoot, "plugin", "skills", "calle", "SKILL.md"),
"---\nname: calle\ndescription: Test skill.\n---\n\n# calle\n",
"---\nname: calle\ndescription: Test skill.\n---\n\n# calle\n\nUse assistant_hint.message to include a brief post-auth help note after auth login.\n",
);
writeFile(
path.join(packageRoot, "plugin", "skills", "calle", "agents", "openai.yaml"),
Expand Down