vidbyte-cli 0.1.0__py3-none-any.whl
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.
- vidbyte_cli/__init__.py +11 -0
- vidbyte_cli/__main__.py +6 -0
- vidbyte_cli/cli.py +18 -0
- vidbyte_cli/commands/__init__.py +86 -0
- vidbyte_cli/commands/agent_options.py +53 -0
- vidbyte_cli/commands/agents/__init__.py +31 -0
- vidbyte_cli/commands/agents/suggestion/__init__.py +38 -0
- vidbyte_cli/commands/agents/suggestion/prompts/__init__.py +3 -0
- vidbyte_cli/commands/agents/suggestion/prompts/all_categories.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/approaches.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/avoid.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/blockers.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/capability.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/categories.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/category.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/completed.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/constraint.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/context.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/count.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/critic_model.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/decision.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/dry_run.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/extra_compute.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/feedback_accept.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/feedback_group.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/feedback_project.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/feedback_reason.md +98 -0
- vidbyte_cli/commands/agents/suggestion/prompts/feedback_reject.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/feedback_suggestion.md +101 -0
- vidbyte_cli/commands/agents/suggestion/prompts/files.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/forbidden.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/goal.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/handoff.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/horizon.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/hypotheses.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/idea.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/in_progress.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/input.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/library.py +29 -0
- vidbyte_cli/commands/agents/suggestion/prompts/max_messages.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/max_output_tokens.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/max_total_tokens.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/mistakes.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/outcomes.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project_create.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project_description.md +98 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project_group.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project_key.md +96 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project_list.md +7 -0
- vidbyte_cli/commands/agents/suggestion/prompts/project_title.md +99 -0
- vidbyte_cli/commands/agents/suggestion/prompts/provider.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/question.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/risks.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/rounds.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/run.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/success.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/timeout.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/trajectory.md +100 -0
- vidbyte_cli/commands/agents/suggestion/prompts/view.md +5 -0
- vidbyte_cli/commands/agents/suggestion/prompts/view_all.md +5 -0
- vidbyte_cli/commands/agents/suggestion/render.py +77 -0
- vidbyte_cli/commands/agents/suggestion/request_builder.py +240 -0
- vidbyte_cli/commands/agents/suggestion/suggest.py +154 -0
- vidbyte_cli/commands/agents/suggestion/suggestion_categories.py +77 -0
- vidbyte_cli/commands/agents/suggestion/suggestion_feedback.py +85 -0
- vidbyte_cli/commands/agents/suggestion/suggestion_handoff.py +67 -0
- vidbyte_cli/commands/agents/suggestion/suggestion_projects.py +95 -0
- vidbyte_cli/commands/auth/__init__.py +0 -0
- vidbyte_cli/commands/auth/login.py +100 -0
- vidbyte_cli/commands/auth/logout.py +41 -0
- vidbyte_cli/commands/auth/whoami.py +51 -0
- vidbyte_cli/commands/billing/__init__.py +20 -0
- vidbyte_cli/commands/billing/prompts/__init__.py +1 -0
- vidbyte_cli/commands/billing/prompts/confirm.md +16 -0
- vidbyte_cli/commands/billing/prompts/group.md +13 -0
- vidbyte_cli/commands/billing/prompts/idempotency_key.md +16 -0
- vidbyte_cli/commands/billing/prompts/library.py +18 -0
- vidbyte_cli/commands/billing/prompts/top_up.md +16 -0
- vidbyte_cli/commands/billing/top_up.py +65 -0
- vidbyte_cli/commands/config/__init__.py +0 -0
- vidbyte_cli/commands/config/get.py +45 -0
- vidbyte_cli/commands/config/set.py +39 -0
- vidbyte_cli/commands/provider/__init__.py +9 -0
- vidbyte_cli/commands/provider/login.py +102 -0
- vidbyte_cli/commands/provider/logout.py +45 -0
- vidbyte_cli/commands/provider/whoami.py +49 -0
- vidbyte_cli/commands/research/__init__.py +5 -0
- vidbyte_cli/commands/research/add.py +41 -0
- vidbyte_cli/commands/research/options.py +134 -0
- vidbyte_cli/commands/research/render.py +157 -0
- vidbyte_cli/commands/research/resume.py +37 -0
- vidbyte_cli/commands/research/start.py +37 -0
- vidbyte_cli/commands/research/status.py +32 -0
- vidbyte_cli/commands/research/thread.py +30 -0
- vidbyte_cli/commands/research/threads.py +35 -0
- vidbyte_cli/commands/research/watch.py +93 -0
- vidbyte_cli/commands/runtime/__init__.py +23 -0
- vidbyte_cli/commands/runtime/adversarial_team.py +41 -0
- vidbyte_cli/commands/runtime/doctor.py +44 -0
- vidbyte_cli/commands/runtime/list.py +47 -0
- vidbyte_cli/commands/runtime/persistence.py +141 -0
- vidbyte_cli/commands/runtime/same_host_ensemble.py +221 -0
- vidbyte_cli/commands/runtime/stages.py +553 -0
- vidbyte_cli/commands/runtime/task_board.py +1342 -0
- vidbyte_cli/commands/setup/__init__.py +0 -0
- vidbyte_cli/commands/setup/doctor.py +64 -0
- vidbyte_cli/commands/setup/prompts/__init__.py +1 -0
- vidbyte_cli/commands/setup/prompts/browser.md +7 -0
- vidbyte_cli/commands/setup/prompts/library.py +18 -0
- vidbyte_cli/commands/setup/prompts/star.md +13 -0
- vidbyte_cli/commands/setup/star.py +132 -0
- vidbyte_cli/lib/__init__.py +0 -0
- vidbyte_cli/lib/api/__init__.py +0 -0
- vidbyte_cli/lib/api/client.py +236 -0
- vidbyte_cli/lib/api/endpoints/__init__.py +0 -0
- vidbyte_cli/lib/api/endpoints/auth.py +24 -0
- vidbyte_cli/lib/api/endpoints/billing.py +36 -0
- vidbyte_cli/lib/api/endpoints/research.py +103 -0
- vidbyte_cli/lib/api/endpoints/runtime.py +113 -0
- vidbyte_cli/lib/api/problem.py +86 -0
- vidbyte_cli/lib/api/response.py +101 -0
- vidbyte_cli/lib/api/retry.py +116 -0
- vidbyte_cli/lib/api/runtime_payment.py +89 -0
- vidbyte_cli/lib/auth/__init__.py +16 -0
- vidbyte_cli/lib/auth/credentials.py +223 -0
- vidbyte_cli/lib/auth/input.py +59 -0
- vidbyte_cli/lib/auth/keyring_store.py +126 -0
- vidbyte_cli/lib/auth/provider_credentials.py +157 -0
- vidbyte_cli/lib/auth/provider_input.py +54 -0
- vidbyte_cli/lib/auth/provider_resolver.py +89 -0
- vidbyte_cli/lib/auth/provider_store.py +149 -0
- vidbyte_cli/lib/auth/provider_verifier.py +219 -0
- vidbyte_cli/lib/auth/resolver.py +63 -0
- vidbyte_cli/lib/auth/verifier.py +38 -0
- vidbyte_cli/lib/config/__init__.py +25 -0
- vidbyte_cli/lib/config/atomic.py +47 -0
- vidbyte_cli/lib/config/config.py +141 -0
- vidbyte_cli/lib/config/migration.py +81 -0
- vidbyte_cli/lib/config/models.py +145 -0
- vidbyte_cli/lib/config/paths.py +66 -0
- vidbyte_cli/lib/config/resolver.py +137 -0
- vidbyte_cli/lib/constants/__init__.py +1 -0
- vidbyte_cli/lib/constants/runtime.py +186 -0
- vidbyte_cli/lib/errors/__init__.py +12 -0
- vidbyte_cli/lib/errors/cli_error.py +86 -0
- vidbyte_cli/lib/errors/codes.py +43 -0
- vidbyte_cli/lib/errors/failures.py +2910 -0
- vidbyte_cli/lib/errors/handler.py +72 -0
- vidbyte_cli/lib/files/__init__.py +6 -0
- vidbyte_cli/lib/files/documents.py +94 -0
- vidbyte_cli/lib/files/store.py +156 -0
- vidbyte_cli/lib/io/__init__.py +16 -0
- vidbyte_cli/lib/io/attachments.py +129 -0
- vidbyte_cli/lib/io/codex_attachments.py +47 -0
- vidbyte_cli/lib/io/prompt.py +71 -0
- vidbyte_cli/lib/io/streams.py +37 -0
- vidbyte_cli/lib/io/terminal.py +66 -0
- vidbyte_cli/lib/output/__init__.py +7 -0
- vidbyte_cli/lib/output/formats.py +29 -0
- vidbyte_cli/lib/output/manager.py +95 -0
- vidbyte_cli/lib/output/models.py +49 -0
- vidbyte_cli/lib/runtime/__init__.py +9 -0
- vidbyte_cli/lib/runtime/application.py +134 -0
- vidbyte_cli/lib/runtime/context.py +250 -0
- vidbyte_cli/lib/runtime/options.py +159 -0
- vidbyte_cli/lib/runtime/version.py +30 -0
- vidbyte_cli/lib/runtime_primitives/__init__.py +28 -0
- vidbyte_cli/lib/runtime_primitives/executor.py +54 -0
- vidbyte_cli/lib/runtime_primitives/gate.py +105 -0
- vidbyte_cli/lib/runtime_primitives/hosts.py +45 -0
- vidbyte_cli/lib/runtime_primitives/planner.py +79 -0
- vidbyte_cli/lib/runtime_primitives/stages.py +338 -0
- vidbyte_cli/lib/runtime_primitives/task_board.py +982 -0
- vidbyte_cli/lib/runtime_primitives/task_board_checkpoints.py +473 -0
- vidbyte_cli/lib/runtime_primitives/task_board_system.md +33 -0
- vidbyte_cli/lib/runtime_primitives/task_board_tasks.py +111 -0
- vidbyte_cli/lib/runtime_primitives/verification.py +68 -0
- vidbyte_cli/services/__init__.py +5 -0
- vidbyte_cli/services/ensemble/__init__.py +7 -0
- vidbyte_cli/services/ensemble/prompts/__init__.py +6 -0
- vidbyte_cli/services/ensemble/prompts/implementer_system.md +546 -0
- vidbyte_cli/services/ensemble/prompts/implementer_turn.md +49 -0
- vidbyte_cli/services/ensemble/prompts/library.py +188 -0
- vidbyte_cli/services/ensemble/prompts/planner_system.md +728 -0
- vidbyte_cli/services/ensemble/prompts/planner_turn.md +6 -0
- vidbyte_cli/services/ensemble/prompts/role_system.md +104 -0
- vidbyte_cli/services/ensemble/prompts/role_turn.md +19 -0
- vidbyte_cli/services/ensemble/prompts/selector_final_turn.md +19 -0
- vidbyte_cli/services/ensemble/prompts/selector_round_turn.md +17 -0
- vidbyte_cli/services/ensemble/prompts/selector_system.md +89 -0
- vidbyte_cli/services/ensemble/runner.py +30 -0
- vidbyte_cli/services/ensemble/sdk.py +134 -0
- vidbyte_cli/services/ensemble/service.py +233 -0
- vidbyte_cli/services/ensemble/settings.py +60 -0
- vidbyte_cli/services/persistence/__init__.py +6 -0
- vidbyte_cli/services/persistence/prompts/__init__.py +6 -0
- vidbyte_cli/services/persistence/prompts/library.py +46 -0
- vidbyte_cli/services/persistence/prompts/persistence_system.md +1 -0
- vidbyte_cli/services/persistence/prompts/persistence_turn.md +3 -0
- vidbyte_cli/services/persistence/runner.py +35 -0
- vidbyte_cli/services/persistence/session.py +116 -0
- vidbyte_cli/services/suggestions/__init__.py +7 -0
- vidbyte_cli/services/suggestions/categories.py +270 -0
- vidbyte_cli/services/suggestions/context.py +222 -0
- vidbyte_cli/services/suggestions/extra_compute.py +53 -0
- vidbyte_cli/services/suggestions/handoff.py +173 -0
- vidbyte_cli/services/suggestions/message_tools.py +47 -0
- vidbyte_cli/services/suggestions/project.py +253 -0
- vidbyte_cli/services/suggestions/prompts/__init__.py +1 -0
- vidbyte_cli/services/suggestions/prompts/categories/__init__.py +3 -0
- vidbyte_cli/services/suggestions/prompts/categories/adjacent_opportunity.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/alternative.md +38 -0
- vidbyte_cli/services/suggestions/prompts/categories/big_bets.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/bottleneck.md +38 -0
- vidbyte_cli/services/suggestions/prompts/categories/business_growth.md +38 -0
- vidbyte_cli/services/suggestions/prompts/categories/completion.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/continuation.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/coordination.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/creative_exploration.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/cross_domain.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/delegation.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/experiment.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/feedback.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/goal_clarification.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/immediate_next_steps.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/investigation.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/learning.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/leverage.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/long_term_directions.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/preparation.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/prerequisite.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/prioritization.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/product_experience.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/quick_wins.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/reframing.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/risk_prevention.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/simplification.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/stop_or_defer.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/strategy.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/technical_possibilities.md +37 -0
- vidbyte_cli/services/suggestions/prompts/categories/verification.md +37 -0
- vidbyte_cli/services/suggestions/prompts/critic.md +209 -0
- vidbyte_cli/services/suggestions/prompts/critic_message.md +8 -0
- vidbyte_cli/services/suggestions/prompts/generator.md +64 -0
- vidbyte_cli/services/suggestions/prompts/library.py +72 -0
- vidbyte_cli/services/suggestions/prompts/message_generator_argument.md +1 -0
- vidbyte_cli/services/suggestions/prompts/message_generator_tool.md +1 -0
- vidbyte_cli/services/suggestions/prompts/message_parent_argument.md +1 -0
- vidbyte_cli/services/suggestions/prompts/message_parent_tool.md +1 -0
- vidbyte_cli/services/suggestions/prompts/message_receipt.md +1 -0
- vidbyte_cli/services/suggestions/prompts/revision.md +8 -0
- vidbyte_cli/services/suggestions/sdk.py +228 -0
- vidbyte_cli/services/suggestions/selection.py +78 -0
- vidbyte_cli/services/suggestions/service.py +540 -0
- vidbyte_cli/types/__init__.py +0 -0
- vidbyte_cli/types/api.py +101 -0
- vidbyte_cli/types/attachments.py +79 -0
- vidbyte_cli/types/ensemble.py +189 -0
- vidbyte_cli/types/provider.py +62 -0
- vidbyte_cli/types/research.py +260 -0
- vidbyte_cli/types/runtime.py +1098 -0
- vidbyte_cli/types/suggestions.py +518 -0
- vidbyte_cli-0.1.0.dist-info/METADATA +335 -0
- vidbyte_cli-0.1.0.dist-info/RECORD +269 -0
- vidbyte_cli-0.1.0.dist-info/WHEEL +5 -0
- vidbyte_cli-0.1.0.dist-info/entry_points.txt +2 -0
- vidbyte_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- vidbyte_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""`vidbyte-cli research start <prompt>` — open a new research thread and admit its first run.
|
|
2
|
+
|
|
3
|
+
Admission returns immediately with durable identifiers rather than blocking: a research run
|
|
4
|
+
outlives a terminal session, and `research watch` is the explicit way to wait for one.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from ...lib.runtime.context import ApplicationContext
|
|
12
|
+
from .options import ResearchRunOptions
|
|
13
|
+
from .render import ResearchRenderer
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ResearchStartCommand:
|
|
17
|
+
def register(self, parent: click.Group) -> None:
|
|
18
|
+
# Options are attached before the group takes the callback, so help lists them in order.
|
|
19
|
+
options = ResearchRunOptions()
|
|
20
|
+
|
|
21
|
+
def _run(context: ApplicationContext, /, **values: object) -> None:
|
|
22
|
+
self.execute(context, values)
|
|
23
|
+
|
|
24
|
+
callback = click.argument("prompt")(click.pass_obj(_run))
|
|
25
|
+
parent.command(name="start", help="Start a new research thread from a prompt")(
|
|
26
|
+
options.apply(callback)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def execute(self, context: ApplicationContext, values: dict[str, object]) -> None:
|
|
30
|
+
# Validates the whole request before a credential is resolved, so a malformed
|
|
31
|
+
# invocation costs neither a keyring lookup nor a round trip.
|
|
32
|
+
options = ResearchRunOptions()
|
|
33
|
+
request = options.build(values)
|
|
34
|
+
key = str(options.key(values))
|
|
35
|
+
accepted = context.research_endpoints().create_run(request, key)
|
|
36
|
+
rendered = ResearchRenderer().accepted(accepted, key)
|
|
37
|
+
context.output().result(rendered.document, rendered.human)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""`vidbyte-cli research status <run_id>` — one run's coarse durable progress.
|
|
2
|
+
|
|
3
|
+
The published status is deliberately thin: state, phase, continuation count, and a timestamp.
|
|
4
|
+
Live source and artifact counts are a web-product surface, not part of the API-key contract,
|
|
5
|
+
so nothing here estimates or invents them.
|
|
6
|
+
|
|
7
|
+
This command cannot tell a caller where to add more work. The status route carries only the
|
|
8
|
+
thread's internal identifier, which is rejected by path validation if it were pasted back, so
|
|
9
|
+
the models drop it — `research threads` is where a usable thread ID comes from.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import click
|
|
15
|
+
|
|
16
|
+
from ...lib.runtime.context import ApplicationContext
|
|
17
|
+
from .render import ResearchRenderer
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ResearchStatusCommand:
|
|
21
|
+
def register(self, parent: click.Group) -> None:
|
|
22
|
+
@parent.command(name="status", help="Show one research run's current status")
|
|
23
|
+
@click.argument("run_id")
|
|
24
|
+
@click.pass_obj
|
|
25
|
+
def _run(context: ApplicationContext, run_id: str) -> None:
|
|
26
|
+
self.execute(context, run_id)
|
|
27
|
+
|
|
28
|
+
def execute(self, context: ApplicationContext, run_id: str) -> None:
|
|
29
|
+
# Reads the run once; `admitting` and `accepted` are progress, not failures.
|
|
30
|
+
run = context.research_endpoints().get_run(run_id)
|
|
31
|
+
rendered = ResearchRenderer().run_status(run)
|
|
32
|
+
context.output().result(rendered.document, rendered.human)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""`vidbyte-cli research thread <thread_id>` — one research thread and its rollup counters.
|
|
2
|
+
|
|
3
|
+
Reads the same thread the portfolio lists, plus the latest run's phase and the favourite flag
|
|
4
|
+
a portfolio row omits. A soft-deleted thread reads as not found, the same as one that never
|
|
5
|
+
existed, because reads are scoped to the caller.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from ...lib.runtime.context import ApplicationContext
|
|
13
|
+
from ...types.research import ThreadId
|
|
14
|
+
from .render import ResearchRenderer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ResearchThreadCommand:
|
|
18
|
+
def register(self, parent: click.Group) -> None:
|
|
19
|
+
@parent.command(name="thread", help="Show one research thread")
|
|
20
|
+
@click.argument("thread_id")
|
|
21
|
+
@click.pass_obj
|
|
22
|
+
def _run(context: ApplicationContext, thread_id: str) -> None:
|
|
23
|
+
self.execute(context, thread_id)
|
|
24
|
+
|
|
25
|
+
def execute(self, context: ApplicationContext, thread_id: str) -> None:
|
|
26
|
+
# The ID guard runs first so a mistyped thread never triggers a credential lookup.
|
|
27
|
+
parsed = ThreadId.parse(thread_id)
|
|
28
|
+
thread = context.research_endpoints().get_thread(str(parsed))
|
|
29
|
+
rendered = ResearchRenderer().thread(thread)
|
|
30
|
+
context.output().result(rendered.document, rendered.human)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""`vidbyte-cli research threads` — one page of the caller's research threads.
|
|
2
|
+
|
|
3
|
+
This and `research start` are the only two places a usable thread ID is minted, which is why
|
|
4
|
+
every row leads with it. Paging is cursor-based: an absent `next_cursor` is the end of the
|
|
5
|
+
collection, and the command never loops on the caller's behalf.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from ...lib.runtime.context import ApplicationContext
|
|
13
|
+
from .render import ResearchRenderer
|
|
14
|
+
|
|
15
|
+
_MAXIMUM_PAGE_SIZE = 100
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ResearchThreadsCommand:
|
|
19
|
+
def register(self, parent: click.Group) -> None:
|
|
20
|
+
@parent.command(name="threads", help="List your research threads")
|
|
21
|
+
@click.option("--cursor", help="Continue from the cursor a previous page reported.")
|
|
22
|
+
@click.option(
|
|
23
|
+
"--limit",
|
|
24
|
+
type=click.IntRange(1, _MAXIMUM_PAGE_SIZE),
|
|
25
|
+
help="How many threads to return. The server picks a default when unset.",
|
|
26
|
+
)
|
|
27
|
+
@click.pass_obj
|
|
28
|
+
def _run(context: ApplicationContext, cursor: str | None, limit: int | None) -> None:
|
|
29
|
+
self.execute(context, cursor, limit)
|
|
30
|
+
|
|
31
|
+
def execute(self, context: ApplicationContext, cursor: str | None, limit: int | None) -> None:
|
|
32
|
+
# Reads exactly one page; the cursor is opaque and is echoed back, never parsed.
|
|
33
|
+
page = context.research_endpoints().get_portfolio(cursor, limit)
|
|
34
|
+
rendered = ResearchRenderer().thread_page(page)
|
|
35
|
+
context.output().result(rendered.document, rendered.human)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""`vidbyte-cli research watch <run_id>` — follow one run until it settles.
|
|
2
|
+
|
|
3
|
+
The interval starts at ten seconds and backs off, which is a rate limit decision rather than
|
|
4
|
+
a taste one. The backend meters API keys on a weighted per-minute budget where starting a run
|
|
5
|
+
costs many times what reading one does, so a tight poll loop can exhaust the same budget the
|
|
6
|
+
caller needs to start their next run.
|
|
7
|
+
|
|
8
|
+
Only coarse transitions are reported. The status route publishes no live counters, so a
|
|
9
|
+
change is detected by fingerprinting exactly what it does publish.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import time
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
|
|
18
|
+
from ...lib.errors.failures import ResearchWatchTimedOut
|
|
19
|
+
from ...lib.runtime.context import ApplicationContext
|
|
20
|
+
from ...types.research import ResearchRunStatus
|
|
21
|
+
from .render import ResearchRenderer
|
|
22
|
+
|
|
23
|
+
_INITIAL_DELAY_SECONDS = 10.0
|
|
24
|
+
_MAXIMUM_DELAY_SECONDS = 60.0
|
|
25
|
+
_BACKOFF_FACTOR = 1.5
|
|
26
|
+
_MAXIMUM_TIMEOUT_SECONDS = 86_400.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ResearchWatchCommand:
|
|
30
|
+
def register(self, parent: click.Group) -> None:
|
|
31
|
+
@parent.command(name="watch", help="Watch one research run until it finishes")
|
|
32
|
+
@click.argument("run_id")
|
|
33
|
+
@click.option(
|
|
34
|
+
"--timeout",
|
|
35
|
+
type=click.FloatRange(1.0, _MAXIMUM_TIMEOUT_SECONDS),
|
|
36
|
+
help="Give up waiting after this many seconds. The run keeps going.",
|
|
37
|
+
)
|
|
38
|
+
@click.pass_obj
|
|
39
|
+
def _run(context: ApplicationContext, run_id: str, timeout: float | None) -> None:
|
|
40
|
+
self.execute(context, run_id, timeout)
|
|
41
|
+
|
|
42
|
+
def execute(self, context: ApplicationContext, run_id: str, timeout: float | None) -> None:
|
|
43
|
+
# Polls to a terminal status, then emits that final snapshot as the one result.
|
|
44
|
+
run = self._poll_until_terminal(context, run_id, timeout)
|
|
45
|
+
rendered = ResearchRenderer().run_status(run)
|
|
46
|
+
context.output().result(rendered.document, rendered.human)
|
|
47
|
+
|
|
48
|
+
def _poll_until_terminal(
|
|
49
|
+
self,
|
|
50
|
+
context: ApplicationContext,
|
|
51
|
+
run_id: str,
|
|
52
|
+
timeout: float | None,
|
|
53
|
+
) -> ResearchRunStatus:
|
|
54
|
+
# Always fetches once before honouring the deadline, so a tiny timeout still reports.
|
|
55
|
+
endpoints = context.research_endpoints()
|
|
56
|
+
renderer = ResearchRenderer()
|
|
57
|
+
started = time.monotonic()
|
|
58
|
+
delay = _INITIAL_DELAY_SECONDS
|
|
59
|
+
last_fingerprint: str | None = None
|
|
60
|
+
while True:
|
|
61
|
+
run = endpoints.get_run(run_id)
|
|
62
|
+
fingerprint = self._fingerprint(run)
|
|
63
|
+
if fingerprint != last_fingerprint:
|
|
64
|
+
self._emit_transition(context, renderer, run)
|
|
65
|
+
last_fingerprint = fingerprint
|
|
66
|
+
if run.status.is_terminal():
|
|
67
|
+
return run
|
|
68
|
+
if self._expired(started, timeout, delay):
|
|
69
|
+
raise ResearchWatchTimedOut(run_id)
|
|
70
|
+
time.sleep(delay)
|
|
71
|
+
delay = self._next_delay(delay)
|
|
72
|
+
|
|
73
|
+
def _fingerprint(self, run: ResearchRunStatus) -> str:
|
|
74
|
+
# The whole of what the status route publishes, so no change can go unnoticed.
|
|
75
|
+
return f"{run.status.value}:{run.phase}:{run.updated_at.isoformat()}"
|
|
76
|
+
|
|
77
|
+
def _emit_transition(
|
|
78
|
+
self,
|
|
79
|
+
context: ApplicationContext,
|
|
80
|
+
renderer: ResearchRenderer,
|
|
81
|
+
run: ResearchRunStatus,
|
|
82
|
+
) -> None:
|
|
83
|
+
# Progress goes to the transition channel so a single-JSON consumer still sees
|
|
84
|
+
# exactly one document on stdout at the end.
|
|
85
|
+
rendered = renderer.transition(run)
|
|
86
|
+
context.output().transition(rendered.document, rendered.human)
|
|
87
|
+
|
|
88
|
+
def _expired(self, started: float, timeout: float | None, delay: float) -> bool:
|
|
89
|
+
# Checked before sleeping: waiting past the deadline to discover it would be worse.
|
|
90
|
+
return timeout is not None and (time.monotonic() - started) + delay >= timeout
|
|
91
|
+
|
|
92
|
+
def _next_delay(self, delay: float) -> float:
|
|
93
|
+
return min(delay * _BACKOFF_FACTOR, _MAXIMUM_DELAY_SECONDS)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Static commands for locally executed Vidbyte runtime primitives.
|
|
2
|
+
|
|
3
|
+
This group is distinct from hosted services because execution remains on the user's
|
|
4
|
+
machine and delegates to an installed native coding-agent host.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .adversarial_team import AdversarialTeamCommand
|
|
8
|
+
from .doctor import RuntimeDoctorCommand
|
|
9
|
+
from .list import RuntimeListCommand
|
|
10
|
+
from .persistence import PersistenceCommand
|
|
11
|
+
from .same_host_ensemble import SameHostEnsembleCommand
|
|
12
|
+
from .stages import StagesCommand
|
|
13
|
+
from .task_board import TaskBoardCommand
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"AdversarialTeamCommand",
|
|
17
|
+
"PersistenceCommand",
|
|
18
|
+
"RuntimeDoctorCommand",
|
|
19
|
+
"RuntimeListCommand",
|
|
20
|
+
"SameHostEnsembleCommand",
|
|
21
|
+
"TaskBoardCommand",
|
|
22
|
+
"StagesCommand",
|
|
23
|
+
]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Command shell for the first local adversarial-team runtime primitive.
|
|
2
|
+
|
|
3
|
+
The command validates host and working-directory context, then reaches the inert executor.
|
|
4
|
+
It cannot request paid admission or spawn agents in this release.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from ...lib.runtime.context import ApplicationContext
|
|
14
|
+
from ...types.runtime import RuntimeHost
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AdversarialTeamCommand:
|
|
18
|
+
"""Builds a launch plan for the unimplemented adversarial-team executor."""
|
|
19
|
+
|
|
20
|
+
def register(self, parent: click.Group) -> None:
|
|
21
|
+
# Attaches the first primitive with an explicit native host selector.
|
|
22
|
+
@parent.command(name="adversarial-team", help="Run an adversarial agent team locally")
|
|
23
|
+
@click.argument("task")
|
|
24
|
+
@click.option(
|
|
25
|
+
"--host",
|
|
26
|
+
type=click.Choice(("auto", *(host.value for host in RuntimeHost))),
|
|
27
|
+
default="auto",
|
|
28
|
+
show_default=True,
|
|
29
|
+
)
|
|
30
|
+
@click.pass_obj
|
|
31
|
+
def _run(context: ApplicationContext, task: str, host: str) -> None:
|
|
32
|
+
# Delegates parsed values to the class-owned execution method.
|
|
33
|
+
self.execute(context, task, host)
|
|
34
|
+
|
|
35
|
+
def execute(self, context: ApplicationContext, task: str, host: str) -> None:
|
|
36
|
+
# Builds a local plan first; the executor then fails before payment or process launch.
|
|
37
|
+
requested = None if host == "auto" else RuntimeHost(host)
|
|
38
|
+
plan = context.runtime_launch_planner().build(
|
|
39
|
+
task, requested, Path.cwd(), "runtime.adversarial-team@1"
|
|
40
|
+
)
|
|
41
|
+
context.runtime_executor().execute_adversarial_team(plan)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""`vidbyte-cli runtime doctor` inspects local native-agent prerequisites.
|
|
2
|
+
|
|
3
|
+
It is read-only and offline: executable paths are reported, while host configuration,
|
|
4
|
+
credentials, environment values, and repository contents are not inspected.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from pydantic import JsonValue
|
|
13
|
+
|
|
14
|
+
from ...lib.output import OutputDocument
|
|
15
|
+
from ...lib.runtime.context import ApplicationContext
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RuntimeDoctorCommand:
|
|
19
|
+
"""Reports the working directory and supported host availability."""
|
|
20
|
+
|
|
21
|
+
def register(self, parent: click.Group) -> None:
|
|
22
|
+
# Attaches the local-only diagnostic beneath the runtime group.
|
|
23
|
+
@parent.command(name="doctor", help="Diagnose local runtime host availability")
|
|
24
|
+
@click.pass_obj
|
|
25
|
+
def _run(context: ApplicationContext) -> None:
|
|
26
|
+
# Delegates command behavior to the class-owned execution method.
|
|
27
|
+
self.execute(context)
|
|
28
|
+
|
|
29
|
+
def execute(self, context: ApplicationContext) -> None:
|
|
30
|
+
# Presents PATH discovery without resolving credentials or opening the network.
|
|
31
|
+
statuses = context.runtime_hosts().inspect()
|
|
32
|
+
working_directory = str(Path.cwd().resolve())
|
|
33
|
+
rows: list[JsonValue] = [status.model_dump(mode="json") for status in statuses]
|
|
34
|
+
human_rows = [
|
|
35
|
+
f"{status.host.value}: {status.executable if status.available else 'not found'}"
|
|
36
|
+
for status in statuses
|
|
37
|
+
]
|
|
38
|
+
human = "\n".join((f"Working directory: {working_directory}", *human_rows))
|
|
39
|
+
context.output().result(
|
|
40
|
+
OutputDocument(
|
|
41
|
+
kind="runtime.doctor", data={"working_directory": working_directory, "hosts": rows}
|
|
42
|
+
),
|
|
43
|
+
human,
|
|
44
|
+
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""`vidbyte-cli runtime list` renders locally executable runtime products.
|
|
2
|
+
|
|
3
|
+
The catalog comes from Vidbyte so price and supported host metadata stay aligned with the
|
|
4
|
+
paid admission route rather than becoming hard-coded command policy.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from pydantic import JsonValue
|
|
11
|
+
|
|
12
|
+
from ...lib.output import OutputDocument
|
|
13
|
+
from ...lib.runtime.context import ApplicationContext
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RuntimeListCommand:
|
|
17
|
+
"""Lists the backend's runtime-only capability catalog."""
|
|
18
|
+
|
|
19
|
+
def register(self, parent: click.Group) -> None:
|
|
20
|
+
# Attaches the authenticated catalog read beneath the runtime group.
|
|
21
|
+
@parent.command(name="list", help="List local runtime primitives and prices")
|
|
22
|
+
@click.pass_obj
|
|
23
|
+
def _run(context: ApplicationContext) -> None:
|
|
24
|
+
# Delegates command behavior to the class-owned execution method.
|
|
25
|
+
self.execute(context)
|
|
26
|
+
|
|
27
|
+
def execute(self, context: ApplicationContext) -> None:
|
|
28
|
+
# Fetches one bounded catalog and renders only its typed public fields.
|
|
29
|
+
catalog = context.runtime_endpoints().list_capabilities()
|
|
30
|
+
rows: list[JsonValue] = [
|
|
31
|
+
capability.model_dump(mode="json") for capability in catalog.capabilities
|
|
32
|
+
]
|
|
33
|
+
human_rows = []
|
|
34
|
+
for item in catalog.capabilities:
|
|
35
|
+
hosts = ", ".join(host.value for host in item.supported_hosts)
|
|
36
|
+
price = item.admission_price_cents / 100
|
|
37
|
+
human_rows.append(
|
|
38
|
+
f"{item.capability_id}@{item.version}: ${price:.2f} per local launch ({hosts})"
|
|
39
|
+
)
|
|
40
|
+
human = "\n".join(human_rows)
|
|
41
|
+
context.output().result(
|
|
42
|
+
OutputDocument(
|
|
43
|
+
kind="runtime.catalog",
|
|
44
|
+
data={"capabilities": rows, "topup_path": catalog.topup_path},
|
|
45
|
+
),
|
|
46
|
+
human or "No local runtime primitives are available.",
|
|
47
|
+
)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Validates and admits one fixed-loop local Codex persistence invocation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from uuid import uuid4
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from ...lib.constants.runtime import PersistenceProgress as Progress
|
|
12
|
+
from ...lib.constants.runtime import RuntimePaymentConfig as PaymentConfig
|
|
13
|
+
from ...lib.errors.failures import RuntimeAdmissionNotVerified
|
|
14
|
+
from ...lib.output import OutputDocument
|
|
15
|
+
from ...lib.runtime.context import ApplicationContext as Context
|
|
16
|
+
from ...lib.runtime_primitives.gate import RuntimeAdmissionGate
|
|
17
|
+
from ...services.persistence.runner import PersistenceRunner
|
|
18
|
+
from ...services.persistence.session import PersistentCodexSession
|
|
19
|
+
from ...types.provider import PROVIDER_ENV_VARS, Provider
|
|
20
|
+
from ...types.runtime import (
|
|
21
|
+
PersistenceSettings,
|
|
22
|
+
PersistenceStrength,
|
|
23
|
+
RuntimeAdmissionRequest,
|
|
24
|
+
RuntimeGrantVerificationRequest,
|
|
25
|
+
RuntimeHost,
|
|
26
|
+
RuntimeX402AdmissionRequest,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
_WITH_X402_PAYMENT_HELP = (
|
|
30
|
+
"Pay the two-cent admission charge with an x402 on-chain transfer instead of debiting "
|
|
31
|
+
"your Vidbyte API balance. The default is the API-balance path, because it needs no "
|
|
32
|
+
"wallet and additionally verifies the exact usage-ledger debit before Codex starts. "
|
|
33
|
+
"Pass this flag when the account holding the work has no Vidbyte balance, or when you "
|
|
34
|
+
"would rather settle admission from a funded wallet. It requires "
|
|
35
|
+
"VIDBYTE_X402_PRIVATE_KEY in the environment and a wallet already holding USDC on "
|
|
36
|
+
"VIDBYTE_X402_NETWORK, which defaults to Base; the CLI never funds the wallet and never "
|
|
37
|
+
"switches payment methods on its own. This changes only how admission is settled: a "
|
|
38
|
+
"Vidbyte API key with runtime:write still establishes ownership, and every model call "
|
|
39
|
+
"is still billed to your own OpenAI credentials."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PersistenceCommand:
|
|
44
|
+
"""Keeps validation and provider credentials ahead of paid admission."""
|
|
45
|
+
|
|
46
|
+
def register(self, parent: click.Group) -> None:
|
|
47
|
+
# The host selector rejects unsupported execution modes before charging.
|
|
48
|
+
@parent.command(name="persistence", help="Persistently drive one local Codex session")
|
|
49
|
+
@click.argument("task")
|
|
50
|
+
@click.option(
|
|
51
|
+
"--host", type=click.Choice(("auto", "codex")), default="codex", expose_value=False
|
|
52
|
+
)
|
|
53
|
+
@click.option("--strength", type=click.IntRange(1, 6), default=1, show_default=True)
|
|
54
|
+
@click.option(
|
|
55
|
+
"--idempotency-key", "key", default=None, help="Reuse only to recover admission."
|
|
56
|
+
)
|
|
57
|
+
@click.option(
|
|
58
|
+
"--with-x402-payment",
|
|
59
|
+
is_flag=True,
|
|
60
|
+
help=_WITH_X402_PAYMENT_HELP,
|
|
61
|
+
)
|
|
62
|
+
@click.pass_obj
|
|
63
|
+
def _run(
|
|
64
|
+
context: Context,
|
|
65
|
+
task: str,
|
|
66
|
+
strength: int,
|
|
67
|
+
key: str | None,
|
|
68
|
+
with_x402_payment: bool,
|
|
69
|
+
) -> None:
|
|
70
|
+
# Delegates without normalizing or wrapping the original task.
|
|
71
|
+
self.execute(context, task, strength, key, with_x402_payment)
|
|
72
|
+
|
|
73
|
+
def execute(
|
|
74
|
+
self,
|
|
75
|
+
context: Context,
|
|
76
|
+
task: str,
|
|
77
|
+
strength: int,
|
|
78
|
+
key: str | None,
|
|
79
|
+
with_x402_payment: bool = False,
|
|
80
|
+
) -> None:
|
|
81
|
+
# Resolve local prerequisites before any wallet admission, then verify before execution.
|
|
82
|
+
progress = context.output().diagnostic
|
|
83
|
+
progress(Progress.PREPARING)
|
|
84
|
+
key = key or str(uuid4())
|
|
85
|
+
if re.fullmatch(r"[A-Za-z0-9._:-]{8,128}", key) is None:
|
|
86
|
+
raise click.BadParameter(
|
|
87
|
+
"Use 8–128 letters, digits, dots, underscores, colons or hyphens."
|
|
88
|
+
)
|
|
89
|
+
plan = context.runtime_launch_planner().build(
|
|
90
|
+
task, RuntimeHost.CODEX, Path.cwd(), "runtime.persistence@1"
|
|
91
|
+
)
|
|
92
|
+
settings = PersistenceSettings(strength=PersistenceStrength(strength))
|
|
93
|
+
progress(Progress.CREDENTIALS)
|
|
94
|
+
session = self._session(context)
|
|
95
|
+
session.prepare(plan)
|
|
96
|
+
endpoints = context.runtime_endpoints()
|
|
97
|
+
progress(f"Admission recovery key: {key}")
|
|
98
|
+
if with_x402_payment:
|
|
99
|
+
from ...lib.api.runtime_payment import RuntimePayment
|
|
100
|
+
|
|
101
|
+
payer = RuntimePayment(context.environment, PaymentConfig.PERSISTENCE_CENTS)
|
|
102
|
+
progress(Progress.X402_ADMISSION)
|
|
103
|
+
request = RuntimeX402AdmissionRequest(host=plan.host)
|
|
104
|
+
grant = endpoints.admit_persistence_x402(request, key, payer)
|
|
105
|
+
else:
|
|
106
|
+
progress(Progress.ADMISSION)
|
|
107
|
+
grant = endpoints.admit_persistence(RuntimeAdmissionRequest(host=plan.host), key)
|
|
108
|
+
if grant.grant_token is None:
|
|
109
|
+
raise RuntimeAdmissionNotVerified("grant_token_missing")
|
|
110
|
+
progress(Progress.VERIFYING)
|
|
111
|
+
verified = endpoints.verify_grant(
|
|
112
|
+
RuntimeGrantVerificationRequest(
|
|
113
|
+
grant_token=grant.grant_token,
|
|
114
|
+
idempotency_key_hash=RuntimeAdmissionGate.hash_idempotency_key(key),
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
verdict = RuntimeAdmissionGate().verify_online(plan, grant, verified)
|
|
118
|
+
if not verdict.admitted:
|
|
119
|
+
raise RuntimeAdmissionNotVerified(verdict.reason)
|
|
120
|
+
progress(Progress.ADMITTED)
|
|
121
|
+
result = PersistenceRunner().run(plan, settings, session, verdict)
|
|
122
|
+
context.output().result(
|
|
123
|
+
OutputDocument(kind="runtime.persistence", data=result.model_dump(mode="json")),
|
|
124
|
+
result.text,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def _session(self, context: Context) -> PersistentCodexSession:
|
|
128
|
+
# The SDK merges env with the parent: empty overrides prevent secret reinheritance.
|
|
129
|
+
credentials = context.require_provider_credentials(Provider.OPENAI)
|
|
130
|
+
environment = dict(context.environment)
|
|
131
|
+
for name in (
|
|
132
|
+
*PROVIDER_ENV_VARS.values(),
|
|
133
|
+
"GOOGLE_API_KEY",
|
|
134
|
+
"VIDBYTE_API_KEY",
|
|
135
|
+
"RUNTIME_ADMISSION_SIGNING_KEY",
|
|
136
|
+
"CODEX_API_KEY",
|
|
137
|
+
PaymentConfig.PRIVATE_KEY_ENV,
|
|
138
|
+
):
|
|
139
|
+
environment[name] = ""
|
|
140
|
+
environment["OPENAI_API_KEY"] = credentials.secret_value()
|
|
141
|
+
return PersistentCodexSession(environment, context.output().diagnostic)
|